IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 各种类型的Map性能如何? --《JAVA编程思想》73 -> 正文阅读

[Java知识库]各种类型的Map性能如何? --《JAVA编程思想》73

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

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;


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

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

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-19 17:30:07  更:2021-11-19 17:31:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:46:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码