各种类型的Map性能如何? --《JAVA编程思想》73

2021/11/18 22:39:56

本文主要是介绍各种类型的Map性能如何? --《JAVA编程思想》73,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

今天和大家一起测试下各种常见 Map 类型在不同操作场景下的性能。

目录

  • 0. 准备工作
  • 1.添加
  • 2.获取
  • 3.移除
  • 4.遍历
  • 5.测试结果汇总

0. 准备工作

制定一个测试模板类,通过泛型兼容各种 Map 类型;定义抽象方法 test() ,用于执行各项测试操作,返回值为测试所花费的时间。

public abstract class MapTest<T extends Map> {

    private T map;

    public abstract long test();

    public MapTest(T map) {
        this.map = map;
    }

    public T getMap() {
        return map;
    }

    public void setMap(T map) {
        this.map = map;
    }
    
}

再准备一个用于执行测试方法的工具类 MapPerformanceTest ,将后续待各项测试方法编写在其中,工具类提供构造测试数据的 getMap() 方法和打印测试信息的 displayHead() 方法。

public class MapPerformanceTest {

    /**
     * 获取指定长度的map
     *
     * @param map  容器
     * @param size 容器长度
     * @param <T>
     * @return
     */
    public static <T extends Map> T getMap(T map, int size) {
        //清空遗留数据
        map.clear();
        for (int i = 0; i < size; i++) {
            map.put(i, i);
        }
        return map;
    }

    /**
     * 打印测试测试
     *
     * @param t          容器
     * @param methodName 测试项目
     * @param <T>
     */
    public static <T> void displayHead(T t, String methodName) {
        System.out.println();
        System.out.println(t.getClass().getSimpleName() + "\t" + methodName);
        System.out.println("容器长度\t操作次数\t平均时间");
    }

}

1.添加

    /**
     * 添加测试
     *
     * @param map  容器
     * @param size 容器长度
     * @param <T>
     */
    public static <T extends Map> void put(T map, int size) {
        MapTest<T> mapTest = new MapTest<T>(map) {
            @Override
            public long test() {
                long startTime = System.nanoTime();
                //复用公共方法
                MapPerformanceTest.getMap(getMap(), size);
                long endTime = System.nanoTime();
                return endTime - startTime;
            }
        };
        //操作时间
        long operateTime = mapTest.test();
        //操作次数
        int count = size;
        //平均操作时间
        long avg = operateTime / count;
        System.out.println(size + "\t" + count + "\t" + avg);
    }

    public static void main(String[] args) {
        Map[] maps = {new TreeMap<Integer, Integer>(), new HashMap(),
                new Hashtable(), new LinkedHashMap(),
                new IdentityHashMap(),
                new WeakHashMap()};
        for (Map map : maps) {
            displayHead(map, "put");
            //使用移位操作符计算操作次数,增强代码可读性
            put(map, 10 << 10);
            put(map, 10 << 12);
            put(map, 10 << 14);
        }
    }
TreeMap	put
容器长度	操作次数	平均时间
10240	10240	791
40960	40960	290
163840	163840	141

HashMap	put
容器长度	操作次数	平均时间
10240	10240	201
40960	40960	103
163840	163840	58

Hashtable	put
容器长度	操作次数	平均时间
10240	10240	228
40960	40960	138
163840	163840	66

LinkedHashMap	put
容器长度	操作次数	平均时间
10240	10240	275
40960	40960	133
163840	163840	243

IdentityHashMap	put
容器长度	操作次数	平均时间
10240	10240	253
40960	40960	216
163840	163840	105

WeakHashMap	put
容器长度	操作次数	平均时间
10240	10240	305
40960	40960	81
163840	163840	57

2.获取

    /**
     * 获取测试
     * @param map 容器
     * @param loops 循环次数
     * @param size 容器长度
     * @param <T>
     */
    public static <T extends Map> void get(T map, int loops, int size) {
        MapTest<T> mapTest = new MapTest<T>(map) {
            @Override
            public long test() {
                long startTime = System.nanoTime();
                //指定随机因子,保证每次运行获得的随机数都是一致的
                Random random = new Random(47);
                for (int i = 0; i < loops; i++) {
                    map.get(random.nextInt(size));
                }
                long endTime = System.nanoTime();
                return endTime - startTime;
            }
        };
        //操作时间
        long operateTime = mapTest.test();
        //操作次数
        int count = loops;
        //平均操作时间
        long avg = operateTime / count;
        System.out.println(size + "\t" + count + "\t" + avg);
    }

    public static void main(String[] args) {
        Map[] maps = {new TreeMap<Integer, Integer>(), new HashMap(),
                new Hashtable(), new LinkedHashMap(),
                new IdentityHashMap(),
                new WeakHashMap()};
        Integer[][] testParams = {{10 << 7, 10 << 10}, {10 << 8, 10 << 12}, {10 << 9, 10 << 14}};
        for (Map map : maps) {
            displayHead(map, "get");
            for (int i = 0; i < testParams.length; i++) {
                int loops = testParams[i][0];
                int size = testParams[i][1];
                map = getMap(map, size);
                get(map, loops, size);
            }
        }
    }
TreeMap	get
容器长度	操作次数	平均时间
10240	1280	1468
40960	2560	521
163840	5120	841

HashMap	get
容器长度	操作次数	平均时间
10240	1280	387
40960	2560	163
163840	5120	238

Hashtable	get
容器长度	操作次数	平均时间
10240	1280	188
40960	2560	114
163840	5120	288

LinkedHashMap	get
容器长度	操作次数	平均时间
10240	1280	173
40960	2560	265
163840	5120	303

IdentityHashMap	get
容器长度	操作次数	平均时间
10240	1280	357
40960	2560	140
163840	5120	146

WeakHashMap	get
容器长度	操作次数	平均时间
10240	1280	343
40960	2560	168
163840	5120	200

3.移除

    /**
     * 移除测试
     *
     * @param map   容器
     * @param loops 循环次数
     * @param size  容器长度
     * @param <T>
     */
    public static <T extends Map> void remove(T map, int loops, int size) {
        MapTest<T> mapTest = new MapTest<T>(map) {
            @Override
            public long test() {
                long startTime = System.nanoTime();
                //指定随机因子,保证每次运行获得的随机数都是一致的
                Random random = new Random(47);
                for (int i = 0; i < loops; i++) {
                    map.remove(random.nextInt(size - loops));
                }
                long endTime = System.nanoTime();
                return endTime - startTime;
            }
        };
        //操作时间
        long operateTime = mapTest.test();
        //操作次数
        int count = loops;
        //平均操作时间
        long avg = operateTime / count;
        System.out.println(size + "\t" + count + "\t" + avg);
    }


    public static void main(String[] args) {
        Map[] maps = {new TreeMap<Integer, Integer>(), new HashMap(),
                new Hashtable(), new LinkedHashMap(),
                new IdentityHashMap(),
                new WeakHashMap()};
        Integer[][] testParams = {{10 << 7, 10 << 10}, {10 << 8, 10 << 12}, {10 << 9, 10 << 14}};
        for (Map map : maps) {
            displayHead(map, "remove");
            for (int i = 0; i < testParams.length; i++) {
                int loops = testParams[i][0];
                int size = testParams[i][1];
                map = getMap(map, size);
                remove(map, loops, size);
            }
        }
    }
TreeMap	remove
容器长度	操作次数	平均时间
10240	1280	3142
40960	2560	745
163840	5120	1172

HashMap	remove
容器长度	操作次数	平均时间
10240	1280	366
40960	2560	206
163840	5120	335

Hashtable	remove
容器长度	操作次数	平均时间
10240	1280	241
40960	2560	144
163840	5120	294

LinkedHashMap	remove
容器长度	操作次数	平均时间
10240	1280	518
40960	2560	163
163840	5120	302

IdentityHashMap	remove
容器长度	操作次数	平均时间
10240	1280	323
40960	2560	150
163840	5120	151

WeakHashMap	remove
容器长度	操作次数	平均时间
10240	1280	432
40960	2560	157
163840	5120	217

4.遍历

    /**
     * 遍历测试
     *
     * @param map  容器
     * @param size 容器长度
     * @param <T>
     */
    public static <T extends Map> void iter(T map, int size) {
        MapTest<T> mapTest = new MapTest<T>(map) {
            @Override
            public long test() {
                long startTime = System.nanoTime();
                Set keySet = map.keySet();
                for (Object key : keySet) {
                    map.get(key);
                }
                long endTime = System.nanoTime();
                return endTime - startTime;
            }
        };
        //操作时间
        long operateTime = mapTest.test();
        //操作次数
        int count = size;
        //平均操作时间
        long avg = operateTime / count;
        System.out.println(size + "\t" + count + "\t" + avg);
    }

    public static void main(String[] args) {
        Map[] maps = {new TreeMap<Integer, Integer>(), new HashMap(),
                new Hashtable(), new LinkedHashMap(),
                new IdentityHashMap(),
                new WeakHashMap()};
        Integer[] testParams = {10 << 10, 10 << 12, 10 << 14};
        for (Map map : maps) {
            displayHead(map, "iter");
            for (int i = 0; i < testParams.length; i++) {
                int size = testParams[i];
                map = getMap(map, size);
                iter(map, size);
            }
        }
    }
TreeMap	iter
容器长度	操作次数	平均时间
10240	10240	415
40960	40960	166
163840	163840	89

HashMap	iter
容器长度	操作次数	平均时间
10240	10240	259
40960	40960	41
163840	163840	20

Hashtable	iter
容器长度	操作次数	平均时间
10240	10240	276
40960	40960	99
163840	163840	28

LinkedHashMap	iter
容器长度	操作次数	平均时间
10240	10240	159
40960	40960	11
163840	163840	15

IdentityHashMap	iter
容器长度	操作次数	平均时间
10240	10240	178
40960	40960	38
163840	163840	66

WeakHashMap	iter
容器长度	操作次数	平均时间
10240	10240	225
40960	40960	58
163840	163840	50

5.测试结果汇总

性能分别按高、中、低表示:

测试项目TreeMapHashMapHashtableLinkedHashMapIdentityHashMapWeakHashMap
添加
获取
移除
遍历

小结
1.Map 中需要频繁添加时,优先选择 HashMap 或者 Hashtable ,Hashtable 中所有的操作都是同步的,所以它是线程安全的,而 HaspMap 不是,故 HaspMap 的性能略强于 Hashtable,再不考虑线程安全的前提下,更推荐使用 HashMap ;WeakHashMap 虽然添加性能高,但其存储的 key 都是弱引用,当 key 值的引用被置为 null时,会自动被垃圾回收,一般用于做缓存,大家可以根据需求酌情选择;

2.在随机获取方面,IdentityHashMap 的性能表现最为优异,但其实根据 “==” 来判断 key 值是否重复,而一般的 Map 都是通过 equals() 和 hashCode() 来判断;

3.在随机移除方面,IdentityHashMap 和 WeakHashMap 的性能最高;

4.HashMap、Hashtable、LinkedHashMap 在遍历方面性能都很优异,如果你对插入顺序有要求,建议使用底层为链表结构的 LinkedHashMap ,其他两个无法保证插入顺序;

5.TreeMap 虽然各方面性能都不佳,但它可以控制 key 的排序,这是其他 Map 类无法替代的;

6.HashMap 一般是我们的首选,各方面性能都不错,如果有特定业务场景再考虑使用其他 Map;


本次分享至此结束,希望本文对你有所帮助,若能点亮下方的**点赞**按钮,在下感激不尽,谢谢您的【**精神支持**】。

若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!



这篇关于各种类型的Map性能如何? --《JAVA编程思想》73的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程