比 HashMap 还快 3 倍!

42 阅读2分钟

比 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