如何高效的遍历Map?你常用的不一定是最快的
微信公众号:大黄奔跑
关注我,可了解更多有趣的面试相关问题。
写在之前
如文章标题所言,遍历Map是开发过程中比较常见的行为,实现的方式也有多种方式,本文带领大家一起看看更加高效的遍历 Map。
『茴』的十种写法
首先一起来看看,有哪些遍历 Map 的方式
1. 利用 iterator 和 Map.Entry
long i = 0;
Iterator<Map.Entry<Integer, Integer>>
it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> pair = it.next();
i += pair.getKey() + pair.getValue();
}
2. 利用 foreach 和Map.Entry
long i = 0;
for (Map.Entry<Integer, Integer> pair
: map.entrySet()) {
i += pair.getKey() + pair.getValue();
}
3. 利用 Java 8中的foreach
这种应该算是比较常见的使用方式,也是比较容易理解的
final long[] i = {0};
map.forEach((k, v) -> i[0] += k + v);
4. 利用keySet 和 foreach
keySet: 获取 map 中所有的 key,然后依次遍历每个 key。
long i = 0;
for (Integer key : map.keySet()) {
i += key + map.get(key);
}
5. 利用keySet and iterator
long i = 0;
Iterator<Integer> itr2 = map.keySet().iterator();
while (itr2.hasNext()) {
Integer key = itr2.next();
i += key + map.get(key);
}
6. 利用for循环和Map.Entry
long i = 0;
for (Iterator<Map.Entry<Integer, Integer>>
entries = map.entrySet().iterator(); entries.hasNext(); ) {
Map.Entry<Integer, Integer> entry = entries.next();
i += entry.getKey() + entry.getValue();
}
7. 利用 Java8 的Stream API
这种是我平时开发中用的最多的方式,简单通俗易懂。
但是其性能如何呢?后续待揭秘。
final long[] i = {0};
map.entrySet().stream()
.forEach(e -> i[0] += e.getKey()
+ e.getValue());
8. 利用Java8 中的 Stream API parallel
不知道有多少人用过 Java8 中的 parallel模式,本质是一种并行处理方式。
性能如何?稍后揭晓。
final long[] i = {0};
map.entrySet().stream().parallel()
.forEach(e -> i[0] += e.getKey() + e.getValue());
9. 利用 Apache 包的 IterableMap of
不行就找找外援试试?
long i = 0;
MapIterator<Integer, Integer> it
= iterableMap.mapIterator();
while (it.hasNext()) {
i += it.next() + it.getValue();
}
10. 利用Eclipse (CS) collections 中的MutableMap
final long[] i = {0};
mutableMap.forEachKeyValue((key, value)
-> {i[0] += key + value;
});
性能测试
测试环境如下:Intel i7-4790 3.60 GHz, 16 GB
场景1:小数据集
测试集为小的Map集合(大约100个元素),各个方法耗时如下:
Benchmark Mode Cnt Score Error Units
test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 µs/op
test10_UsingEclipseMap avgt 10 0.309 ± 0.009 µs/op
test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 µs/op
test6_UsingForAndIterator avgt 10 0.387 ± 0.016 µs/op
test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 µs/op
test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 µs/op
test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 µs/op
test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 µs/op
test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 µs/op
test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 µs/op
从结果看出,在数据量比较小时,利用 Java 8中的foreach 暂时领先。
场景2:中等数据集
测试集为元素数据量 1000 的 Map 集合,测试结果如下:
Benchmark Mode Cnt Score Error Units
test10_UsingEclipseMap avgt 10 37.606 ± 0.790 µs/op
test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 µs/op
test6_UsingForAndIterator avgt 10 50.332 ± 0.507 µs/op
test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 µs/op
test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 µs/op
test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 µs/op
test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 µs/op
test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 µs/op
test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 µs/op
test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 µs/op
从结果集合看,在中等数据量情况下,外援 Eclipse (CS) collections 中的 MutableMap 表现最为优异,勇得第一。
其次为 Java 8中的 foreach,位列第二。
场景3:大数据集
测试集为元素数据量 100000(十万级别) 的 Map 集合,测试结果如下:
Benchmark Mode Cnt Score Error Units
test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 µs/op
test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 µs/op
test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 µs/op
test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 µs/op
test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 µs/op
test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 µs/op
test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 µs/op
test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 µs/op
test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 µs/op
test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 µs/op
利用 iterator 和 Map.Entry 【方法1】稳居第一,领先 第二名差不多7s。
第二名为 Eclipse (CS) collections 中的 MutableMap 位列第二,在大数据量下表现表现比较出色。
指的注意的是之前在小数据量下表现比较出色的 Java 8中的 foreach,排名却比较靠后,但是仍然超过了利用 Java8 的Stream API。
其中还有另一个现象:利用并行模式计算的 Java8 中的 Stream API parallel,在大数据量时表现好于 foreach 和 stream api。
总结性能
下表为不同数据量情况下的各个方法性能表现
100 600 1100 1600 2100
test10 0.333 1.631 2.752 5.937 8.024
test3 0.309 1.971 4.147 8.147 10.473
test6 0.372 2.190 4.470 8.322 10.531
test1 0.405 2.237 4.616 8.645 10.707
test2 0.376 2.267 4.809 8.403 10.910
test7 0.473 2.448 5.668 9.790 12.125
test9 0.565 2.830 5.952 13.220 16.965
test4 0.808 5.012 8.813 13.939 17.407
test5 0.810 5.104 8.533 14.064 17.422
test8 5.173 12.499 17.351 24.671 30.403
在平时开发中,数据量都不算太大时,剖除外援而言, Java 8 中的 foreach 【方法3】,表现比较优异。而并行运算的 Stream API parallel【方法8】表现没有想象中好,Stream API【方法7】表现中规中矩。
总结
主要罗列了多种遍历 Map 的方式,每个实现方式都有各自的特点,有的人喜欢 foreach 的通俗易懂;有的人喜欢 stream 的干净利落。
如果从性能来看,小数据量情况下:优先推荐使用 Java8 Foreach【方法3】。
大数据量情况下推荐 使用 iterator 和 Map.Entry【方法1】。
本文非原创文章,翻译自stackoverflow 上的How do I efficiently iterate over each entry in a Java Map?问题答案之一。
原文地址为:(https://stackoverflow.com/questions/46898/how-do-i-efficiently-iterate-over-each-entry-in-a-java-map
也可以通过阅读原文跳转。
我是大黄,一个只会写 HelloWorld 的程序员,下期见。
如何高效的遍历Map?你常用的不一定是最快的的更多相关文章
- 更加高效的遍历 Map
https://stackoverflow.com/questions/46898/how-do-i-efficiently-iterate-over-each-entry-in-a-java-map ...
- Java中关于 ArrayList 和 Map 的常用遍历方法 (学习笔记,便于以后查询)
一.学习ArrayList与Map时,关于常用遍历方法的记录如下: 二.附源码如下: package com.study.in.myself; import java.util.ArrayList; ...
- Java中遍历Map集合的四种方法
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
- Java中如何遍历Map对象的4种方法
在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都实现了Map接口,以下方法适用于任何map实现(HashMap, TreeMap, LinkedHa ...
- java遍历map的四种方式
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
- 转!! Java中如何遍历Map对象的4种方法
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
- 【转】Java中如何遍历Map对
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
- 【转】Java中如何遍历Map对象的4种方法
原文网址:http://blog.csdn.net/tjcyjd/article/details/11111401 在Java中如何遍历Map对象 How to Iterate Over a Map ...
- Java遍历Map对象的四种方法
在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都实现了Map接口,以下方法适用于任何map实现(HashMap, TreeMap, LinkedHa ...
随机推荐
- cxf实例异常
基于CXF2.3.0 Caused by: java.lang.InstantiationException: org.apache.cxf.wstx_msv_validation.WoodstoxV ...
- Pygame基础(1)
Pygame是Python的一个很常用的游戏框架,今天我来讲一讲Pygame的基础知识 Pygame的官网:https://www.pygame.org/news Pygame的下载 打开cmd输入p ...
- springboot项目打包成jar包在Linux服务器默认80端口运行
springboot项目端口设置 在application.properties文件 server.port=80 在application.yml文件 server: port: 80 然后在ide ...
- 146. LRU 缓存机制 + 哈希表 + 自定义双向链表
146. LRU 缓存机制 LeetCode-146 题目描述 题解分析 java代码 package com.walegarrett.interview; /** * @Author WaleGar ...
- 链表算法题之中等级别,debug调试更简单
文章简述 大家好,本篇是个人的第 5 篇文章 从本篇文章开始,分享关于链表的题目为中等难度,本次共有 3 道题目. 一,两数相加 1.1 题目分析 题中写到数字是按照逆序的方式存储,从进位的角度看,两 ...
- 记录安装freeswitch的日常
已知安装版本:Linux:Centos7 Freeswitch:1.10.2 解: 注意:(最好呢是先下载好包,然后上传到这个所用的环境中) 1.安装对应依赖 yum install -y git a ...
- 无限可能 | Flutter 2 重点更新一览
我们非常高兴在本周发布了 Flutter 2.自 Flutter 1.0 发布至今已有两年多的时间,在如此短暂的时间内,我们解决了 24,541 个 issue,合并了来自 765 个贡献者的 17, ...
- Linux Shell 统计一(行\列)数值的总和及行、列转换
(对一列数字求和) 在日常工作当中需要对文本过滤出来的数字进行求和运算,例如想统计一个MySQL分区表现在有多大 # ls -lsh AdPlateform#P#p*.ibd |grep G 2.6 ...
- IgniteMe -高校网络信息安全运维挑战赛
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 void *v3; // eax 4 int v4; ...
- Python的多进程和多线程
进程和线程 进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小单位: 一个应用程序至少包含一个进程,一个进程至少包含一个线程: 每个进程在执行过程中拥有独立的内存空间,而一个进程中的线程之 ...