当前位置: 首页 > java >正文

Map遍历方式效率分析

文章目录

    • 概要
    • 本地环境
    • 测试数据
    • Map遍历方式
      • keySet的Iterator遍历(key、value)
        • 遍历key
        • 遍历value
        • 遍历key+value
      • keySet的for遍历(key、value)
        • 遍历key
        • 遍历value
        • 遍历key+value
      • entrySet的Iterator遍历(key、value)
        • 遍历key
        • 遍历value
        • 遍历key+value
      • entrySet的for遍历(key、value)
        • 遍历key
        • 遍历value
        • 遍历key+value
      • values的Iterator遍历(value)
      • values的for遍历(value)
    • 测试工具
    • 数据运行结果
    • 总结

概要

项目中我们经常会用到Map,也不可避免的需要遍历Map。偶然间刷到一篇文章,不推荐用keySet()遍历HashMap,推荐使用entrySet()进行遍历。给出的理由是keySet()遍历需要经历两次遍历,一次是转为Iterator对象,另一次是是从HashMap中取出key所对应的value;而entrySet()遍历只需要经历一次遍历。这里就不再分析底层的运行逻辑,而是以简单直观的数据运行来展示各遍历方式的效率。

本地环境

处理器:12th Gen Intel® Core™ i5-12500 3.00 GHz
机带RAM:32.0 GB
IDE:Eclipse 2024-09 (4.33.0)
JDK:jdk1.8.0_152

测试数据

准备两对数据(interval分别为1和100):
第一队:1开始,每次增加1,即1,2,3,…
第二队:100开始,每次增加100,即100,200,300,…
准备五组对照组(size分别为1000、10000、100000、1000000和10000000)
数据获取代码如下:

    public static Map<String, String> getNumberMap(int size, int interval) {Map<String, String> map = new HashMap<String, String>();String key, value;for (int i = 1; i <= size; i++) {key = "K" + i * interval;value = "V" + i * interval;map.put(key, value);}return map;}

Map遍历方式

keySet的Iterator遍历(key、value)

遍历key
    public static void keySetIterator4K(Map<String, String> map) {Iterator<String> iterator = map.keySet().iterator();String key;while (iterator.hasNext()) {key = iterator.next();}}
遍历value
    public static void keySetIterator4V(Map<String, String> map) {Iterator<String> iterator = map.keySet().iterator();String value;while (iterator.hasNext()) {value = map.get(iterator.next());}}
遍历key+value
    public static void keySetIterator4KV(Map<String, String> map) {Iterator<String> iterator = map.keySet().iterator();String key, value;while (iterator.hasNext()) {key = iterator.next();value = map.get(key);}}

keySet的for遍历(key、value)

遍历key
    public static void keySetFor4K(Map<String, String> map) {for (String key : map.keySet()) {}}
遍历value
    public static void keySetFor4V(Map<String, String> map) {String value;for (String key : map.keySet()) {value = map.get(key);}}
遍历key+value
    public static void keySetFor4KV(Map<String, String> map) {String value;for (String key : map.keySet()) {value = map.get(key);}}

entrySet的Iterator遍历(key、value)

遍历key
    public static void entrySetIterator4K(Map<String, String> map) {Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();String key;while (iterator.hasNext()) {key = iterator.next().getKey();}}
遍历value
    public static void entrySetIterator4V(Map<String, String> map) {Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();String value;while (iterator.hasNext()) {value = iterator.next().getValue();}}
遍历key+value
    public static void entrySetIterator4KV(Map<String, String> map) {Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();Map.Entry<String, String> entry;String key, value;while (iterator.hasNext()) {entry = iterator.next();key = entry.getKey();value = entry.getValue();}}

entrySet的for遍历(key、value)

遍历key
    public static void entrySetFor4K(Map<String, String> map) {String key;for (Map.Entry<String, String> entry : map.entrySet()) {key = entry.getKey();}}
遍历value
    public static void entrySetFor4V(Map<String, String> map) {String value;for (Map.Entry<String, String> entry : map.entrySet()) {value = entry.getValue();}}
遍历key+value
    public static void entrySetFor4KV(Map<String, String> map) {String key, value;for (Map.Entry<String, String> entry : map.entrySet()) {key = entry.getKey();value = entry.getValue();}}

values的Iterator遍历(value)

    public static void valuesIterator4V(Map<String, String> map) {Iterator<String> iterator = map.values().iterator();String value;while (iterator.hasNext()) {value = iterator.next();}}

values的for遍历(value)

    public static void valuesFor4V(Map<String, String> map) {for (String value : map.values()) {}}

测试工具

    public static void main(String[] args) {int count = 1; // 测试执行次数int[] size = {1000, 10000, 100000, 1000000, 10000000}; // 数据量int[] interval = {1, 100}; // 初始及增长long startTime, endTime;for (int i = 1; i <= count; i++) {System.out.println("第" + i + "次测试:");for (int j = 0; j < size.length; j++) {System.out.println("    size=" + size[j] + ":");for (int k = 0; k < interval.length; k++) {StringBuffer result = new StringBuffer();Map<String, String> map = getNumberMap(size[j], interval[k]);/*** 遍历key*/startTime = System.currentTimeMillis();keySetIterator4K(map); // keySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();keySetFor4K(map); // keySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetIterator4K(map); // entrySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetFor4K(map); // entrySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);/*** 遍历value*/startTime = System.currentTimeMillis();keySetIterator4V(map); // keySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();keySetFor4V(map); // keySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetIterator4V(map); // entrySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetFor4V(map); // entrySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();valuesIterator4V(map); // values的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();valuesFor4V(map); // values的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);/*** 遍历key+value*/startTime = System.currentTimeMillis();keySetIterator4KV(map); // keySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();keySetFor4KV(map); // keySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetIterator4KV(map); // entrySet的Iterator遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);getResultTime(startTime, endTime, result);startTime = System.currentTimeMillis();entrySetFor4KV(map); // entrySet的for遍历endTime = System.currentTimeMillis();getResultTime(startTime, endTime, result);System.out.println("        " + result.toString());}}}}
    public static void getResultTime(long startTime, long endTime, StringBuffer result) {String time = String.valueOf(endTime - startTime);if (result.toString().isEmpty()) {result.append(time);} else {result.append(" 、" + time);}}

数据运行结果

Map遍历方式效率分析
遍历场景遍历方式测试数据耗时(ms)
数据量1000数据量10000数据量100000数据量1000000数据量10000000
数据1数据100数据1数据100数据1数据100数据1数据100数据1数据100
keykeySet的Iterator遍历1011541627138167
keySet的for遍历0011331425148166
entrySet的Iterator遍历1021541627153179
entrySet的for遍历0001431526156177
valuekeySet的Iterator遍历0010571936216212
keySet的for遍历0011462036222215
entrySet的Iterator遍历0101431626156172
entrySet的for遍历0000441526160175
values的Iterator遍历1011431525150162
values的for遍历0000431425148162
key+valuekeySet的Iterator遍历0010552037210214
keySet的for遍历0010551937213210
entrySet的Iterator遍历0010541627164178
entrySet的for遍历1010431728168177

总结

对比上面表格做出以下总结:
1、当Map的size在100000及以下时,各种遍历方式之间差别不大
2、当Map的size为100000,字符串长度最大为9时,多数遍历方式出现字符串长度大遍历效率高(?)
3、当Map的size为100w以上时,可以明显看出keySet的Iterator遍历和for遍历在遍历value时耗时高于其他遍历方式
4、当Map的size为1000w,字符串长度最大为11时,字符串长度对遍历效率的影响变小(?)

所以,遍历HashMap时,如果只是遍历key或者数据量小于10000(?)时,那么无论哪种方式都是可以使用的;如果涉及到value的遍历,那么尽量避免使用keySet()相关的遍历。

http://www.xdnf.cn/news/4620.html

相关文章:

  • 学而思课程视频下载,小学1-6年级
  • 【大模型系列】使用fastapi为langchain应用快速对外提供restful api
  • 路由交换机的 ROMMON 模式
  • 鸿蒙 使用动画 简单使用
  • 学习黑客Linux 系统状态管理
  • 【Python】算法笔记
  • C++ 线程池:原理、实现与高级实现
  • 电商双11美妆数据分析(2)
  • 【anylogic_04】地铁站的人流仿真
  • 易境通海外仓系统:如何高效管理尾程派送订单?
  • 1:点云处理—三种显示方法(自建点云)
  • 这些单词有什么内在联系吗?
  • Linux 内核学习(6) --- Linux 内核基础知识
  • 第18篇:Linux设备驱动程序入门<五>
  • 股票基础知识 | 投资理财(1)【未完待续】
  • 【PhysUnits】2 Scalar<T> 标量元组结构体(scalar/mod.rs)
  • leetcode刷题日记——随机链表的复制
  • 应急响应靶场web3:知攻善防实验室
  • 使用英伟达 Riva 和 OpenAI 构建 AI 聊天机器人
  • 普通IT的股票交易成长史--20250507晚复盘
  • J2 WebScarab 安装指南详细步骤与配置方法
  • 数据报(Datagram)与虚电路(Virtual Circuit)的区别
  • SQL Server 存储过程开发三层结构规范
  • 生物化学笔记:神经生物学概论12 大脑全景图 知觉、行为和语言 注意力
  • vue3的页面跳转方法汇总(路由跳转,组件跳转)
  • 微信小程序开发,登录注册实现
  • ​​Dongle​​(中文常称“加密狗”或“适配器”)
  • 智慧医疗时代下的医疗设备智能控费系统解决方案
  • 【C++】C++中的类型转换
  • GoFrame框架下优雅使用Redis:从入门到实战的最佳实践