比 HashMap 还快 3 倍!
Key 如果是基本数据类型可以使用 Int2ObjectOpenHashMap 替换 HashMap 效率更高
maven 依赖
<!-- https://mvnrepository.com/artifact/it.unimi.dsi/fastutil -->
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>fastutil</artifactId>
<version>8.5.12</version>
</dependency>
import java.util.Random;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class FastUtilBench {
public static void main(String[] args) {
int N = 3_000_000;
int Q = 10_000_000;
Random r = new Random(1);
Int2ObjectOpenHashMap<Integer> m = new Int2ObjectOpenHashMap<>(N, 0.75f);
for (int i = 0; i < N; i++) {
m.put(i, Integer.valueOf(i));
};
// warmup
for (int i = 0; i < 2; i++) {
for (int j = 0; j < Q / 10; j++) m.get(r.nextInt(N));
}
long t0 = System.nanoTime();
for (int j = 0; j < Q; j++) m.get(r.nextInt(N));
long t1 = System.nanoTime();
System.out.println("fastutil time ms: " + ((t1 - t0) / 1_000_000));
}
}
最终的测试结果:fastutil time ms: 602
import java.util.Random;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class FastUtilBench {
public static void main(String[] args) {
int N = 3_000_000;
int Q = 10_000_000;
Random r = new Random(1);
Int2ObjectOpenHashMap<Integer> m = new Int2ObjectOpenHashMap<>(N, 0.75f);
for (int i = 0; i < N; i++) {
m.put(i, Integer.valueOf(i));
};
// warmup
for (int i = 0; i < 2; i++) {
for (int j = 0; j < Q / 10; j++) m.get(r.nextInt(N));
}
long t0 = System.nanoTime();
for (int j = 0; j < Q; j++) m.get(r.nextInt(N));
long t1 = System.nanoTime();
System.out.println("fastutil time ms: " + ((t1 - t0) / 1_000_000));
}
}
还有更快的版本也就是如果 Valude 也是基本数据类型的话可以速度更快
import java.util.Random;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class FastUtilBench {
public static void main(String[] args) {
int N = 3_000_000;
int Q = 10_000_000;
Random r = new Random(1);
Int2IntOpenHashMap m = new Int2IntOpenHashMap(N, 0.75f);
for (int i = 0; i < N; i++) {
m.put(i, i);
};
// warmup
for (int i = 0; i < 2; i++) {
for (int j = 0; j < Q / 10; j++) m.get(r.nextInt(N));
}
long t0 = System.nanoTime();
for (int j = 0; j < Q; j++) m.get(r.nextInt(N));
long t1 = System.nanoTime();
System.out.println("fastutil time ms: " + ((t1 - t0) / 1_000_000));
}
}
fastutil time ms: 552
当然还有其他很多基本数据类型的 key
甚至还有 key 和 value 都是基本数据类型的
HashMap 结果
public class HashMapBoxingBench {
public static void main(String[] args) {
int N = 3_000_000;
int Q = 10_000_000;
List<Integer> keys = new ArrayList<>(N);
Random r = new Random(1);
for (int i = 0; i < N; i++) keys.add(i);
Map<Integer, Integer> m = new HashMap<>(N * 2);
for (int k : keys)
m.put(k, k); // warmup
for (int i = 0; i < 2; i++) {
for (int j = 0; j < Q / 10; j++) m.get(r.nextInt(N));
}
long t0 = System.nanoTime();
for (int j = 0; j < Q; j++) m.get(r.nextInt(N));
long t1 = System.nanoTime();
System.out.println("HashMap time ms: " + ((t1 - t0) / 1_000_000));
}
}
最终测试结果:HashMap time ms: 1765
为什么有时间差异?
因为类型装箱和拆箱带来的性能损失,具体位置是 你调用 get 时传入的参数 和 put 时存入的 key/value 上照成的性能损失
这里传入的是 k 是 int 类型的,含有隐式装箱 Integer.valueOf(k)
在 get 的时候也涉及到了隐式类型转换 r.nexInt() 返回的类型是 int ,然而 get 需要传入的参数类型是 Object