hashMap 应该是java程序员工作中用的比较多的一个键值对处理的数据的类型了。这种数据类型一般都会有增删查的方法,今天我们就来看看它的循环方法以前写过一篇关于ArrayList的循环效率问题《ArrayList哪种遍历效率最好,你真的弄明白了吗?》,感兴趣的同学可以去看看。hashMap 有常见的六七种遍历的方式。这么多的选择,大家平时都是使用哪一种来遍历数据列?欢迎大家在下方留言哦。说实话这么多种方式,想记也不记不住,也不想浪费时间来记这玩意,所以本人在JDK1.8以前基本上都是用Map.Entry的方式来遍历,1.8及以后就习惯性用forEach了,不过这个不能有continue或者break操作这个有时候还是挺不方便的,其他几种基本上没怎么用过,也没太研究这几种方式,哪种性能是比较好的。反正就是挑自己熟悉的方式。好了话不多说,我们还是直入今天的主题。先来看看每种遍历的方式:

在for循环中使用entries实现Map的遍历
 public static void forEachEntries() {
for (Map.Entry<String, String> entry : map.entrySet()) {
String mapKey = entry.getKey();
String mapValue = entry.getValue();
}
}
在for循环中遍历key
 public static void forEachKey() {
for (String key : map.keySet()) {
String mapKey = key;
String mapValue = map.get(mapKey);
}
}
在for循环中遍历value
 public static void forEachValues() {
for (String key : map.values()) {
String val = key;
}
}

Iterator遍历

public static void forEachIterator() {
Iterator<Entry<String, String>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
}
}

forEach jdk1.8遍历

 public static void forEach() {
map.forEach((key, val) -> {
String key1 = key;
String value = val;
});
}

Stream jdk1.8遍历

  map.entrySet().stream().forEach((entry) -> {
String key = entry.getKey();
String value = entry.getValue();
});

Streamparallel jdk1.8遍历

 public static void forEachStreamparallel() {
map.entrySet().parallelStream().forEach((entry) -> {
String key = entry.getKey();
String value = entry.getValue();
});
}

以上就是常见的对于map的一些遍历的方式,下面我们来写个测试用例来看下这些遍历方式,哪些是效率最好的。下面测试用例是基于JMH来测试的
首先引入pom

	 <dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.23</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.23</version>
<scope>provided</scope>
</dependency>

关于jmh测试如可能会影响结果的一些因素这里就不详细介绍了,可以参考文末的第一个链接写的非常详细。以及测试用例为什么要这么写(都是为了消除JIT对测试代码的影响)这是参照官网的链接
编写测试代码如下:

package com.workit.autoconfigure.autoconfigure.controller;

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.TimeUnit; /**
* @author:公众号: java金融
* @Date:
* @Description:微信搜一搜【java金融】回复666
*/ @State(Scope.Thread)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class InstructionsBenchmark {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(InstructionsBenchmark.class.getSimpleName()).result("result.json").resultFormat(ResultFormatType.JSON).build();
new Runner(opt).run();
} static final int BASE = 42; static int add(int key,int val) {
return BASE + key +val;
}
@Param({"1", "10", "100", "1000","10000","100000"})
int size;
private static Map<Integer, Integer> map; // 初始化方法,在全部Benchmark运行之前进行
@Setup(Level.Trial)
public void init() {
map = new HashMap<>(size);
for (int i = 0; i < size; i++) {
map.put(i, i);
}
} /**
* 在for循环中使用entries实现Map的遍历:
*/
@Benchmark
public static void forEachEntries(Blackhole blackhole) {
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
Integer mapKey = entry.getKey();
Integer mapValue = entry.getValue();
blackhole.consume(add(mapKey,mapValue));
}
} /**
* 在for循环中遍历key
*/
@Benchmark
public static StringBuffer forEachKey(Blackhole blackhole) {
StringBuffer stringBuffer = new StringBuffer();
for (Integer key : map.keySet()) {
// Integer mapValue = map.get(key);
blackhole.consume(add(key,key));
}
return stringBuffer;
} /**
* 在for循环中遍历value
*/
@Benchmark
public static void forEachValues(Blackhole blackhole) {
for (Integer key : map.values()) {
blackhole.consume(add(key,key));
}
} /**
* Iterator遍历;
*/
@Benchmark
public static void forEachIterator(Blackhole blackhole) {
Iterator<Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Entry<Integer, Integer> entry = entries.next();
Integer key = entry.getKey();
Integer value = entry.getValue();
blackhole.consume(add(key,value));
}
} /**
* forEach jdk1.8遍历
*/
@Benchmark
public static void forEachLamada(Blackhole blackhole) {
map.forEach((key, value) -> {
blackhole.consume(add(key,value));
}); } /**
* forEach jdk1.8遍历
*/
@Benchmark
public static void forEachStream(Blackhole blackhole) {
map.entrySet().stream().forEach((entry) -> {
Integer key = entry.getKey();
Integer value = entry.getValue();
blackhole.consume(add(key,value)); });
} @Benchmark
public static void forEachStreamparallel(Blackhole blackhole) {
map.entrySet().parallelStream().forEach((entry) -> {
Integer key = entry.getKey();
Integer value = entry.getValue();
blackhole.consume(add(key,value)); });
} }

运行结果如下:
注:运行环境idea 2019.3,jdk1.8,windows7 64位。


Benchmark (size) Mode Cnt Score Error Units
InstructionsBenchmark.forEachEntries 1 avgt 5 10.021 ± 0.224 ns/op
InstructionsBenchmark.forEachEntries 10 avgt 5 71.709 ± 2.537 ns/op
InstructionsBenchmark.forEachEntries 100 avgt 5 738.873 ± 12.132 ns/op
InstructionsBenchmark.forEachEntries 1000 avgt 5 7804.431 ± 136.635 ns/op
InstructionsBenchmark.forEachEntries 10000 avgt 5 88540.345 ± 14915.682 ns/op
InstructionsBenchmark.forEachEntries 100000 avgt 5 1083347.001 ± 136865.960 ns/op
InstructionsBenchmark.forEachIterator 1 avgt 5 10.675 ± 2.532 ns/op
InstructionsBenchmark.forEachIterator 10 avgt 5 73.934 ± 4.517 ns/op
InstructionsBenchmark.forEachIterator 100 avgt 5 775.847 ± 198.806 ns/op
InstructionsBenchmark.forEachIterator 1000 avgt 5 8905.041 ± 1294.618 ns/op
InstructionsBenchmark.forEachIterator 10000 avgt 5 98686.478 ± 10944.570 ns/op
InstructionsBenchmark.forEachIterator 100000 avgt 5 1045309.216 ± 36957.608 ns/op
InstructionsBenchmark.forEachKey 1 avgt 5 18.478 ± 1.344 ns/op
InstructionsBenchmark.forEachKey 10 avgt 5 76.398 ± 12.179 ns/op
InstructionsBenchmark.forEachKey 100 avgt 5 768.507 ± 23.892 ns/op
InstructionsBenchmark.forEachKey 1000 avgt 5 11117.896 ± 1665.021 ns/op
InstructionsBenchmark.forEachKey 10000 avgt 5 84871.880 ± 12056.592 ns/op
InstructionsBenchmark.forEachKey 100000 avgt 5 1114948.566 ± 65582.709 ns/op
InstructionsBenchmark.forEachLamada 1 avgt 5 9.444 ± 0.607 ns/op
InstructionsBenchmark.forEachLamada 10 avgt 5 76.125 ± 5.640 ns/op
InstructionsBenchmark.forEachLamada 100 avgt 5 861.601 ± 98.045 ns/op
InstructionsBenchmark.forEachLamada 1000 avgt 5 7769.714 ± 1663.914 ns/op
InstructionsBenchmark.forEachLamada 10000 avgt 5 73250.238 ± 6032.161 ns/op
InstructionsBenchmark.forEachLamada 100000 avgt 5 836781.987 ± 72125.745 ns/op
InstructionsBenchmark.forEachStream 1 avgt 5 29.113 ± 3.275 ns/op
InstructionsBenchmark.forEachStream 10 avgt 5 117.951 ± 13.755 ns/op
InstructionsBenchmark.forEachStream 100 avgt 5 1064.767 ± 66.869 ns/op
InstructionsBenchmark.forEachStream 1000 avgt 5 9969.549 ± 342.483 ns/op
InstructionsBenchmark.forEachStream 10000 avgt 5 93154.061 ± 7638.122 ns/op
InstructionsBenchmark.forEachStream 100000 avgt 5 1113961.590 ± 218662.668 ns/op
InstructionsBenchmark.forEachStreamparallel 1 avgt 5 65.466 ± 5.519 ns/op
InstructionsBenchmark.forEachStreamparallel 10 avgt 5 2298.999 ± 721.455 ns/op
InstructionsBenchmark.forEachStreamparallel 100 avgt 5 8270.759 ± 1801.082 ns/op
InstructionsBenchmark.forEachStreamparallel 1000 avgt 5 16049.564 ± 1972.856 ns/op
InstructionsBenchmark.forEachStreamparallel 10000 avgt 5 69230.849 ± 12169.260 ns/op
InstructionsBenchmark.forEachStreamparallel 100000 avgt 5 638129.559 ± 14885.962 ns/op
InstructionsBenchmark.forEachValues 1 avgt 5 9.743 ± 2.770 ns/op
InstructionsBenchmark.forEachValues 10 avgt 5 70.761 ± 16.574 ns/op
InstructionsBenchmark.forEachValues 100 avgt 5 745.069 ± 329.548 ns/op
InstructionsBenchmark.forEachValues 1000 avgt 5 7772.584 ± 1702.295 ns/op
InstructionsBenchmark.forEachValues 10000 avgt 5 74063.468 ± 23752.678 ns/op
InstructionsBenchmark.forEachValues 100000 avgt 5 994057.370 ± 279310.867 ns/op


通过上述的图我们可以发现,数据量较小的时候forEachEntriesforEachIterator、以及lamada循环效率都差不多forEachStreamarallel的效率反而较低,只有当数据量达到10000以上parallelStream的优势就体现出来了。所以平时选择使用哪种循环方式的时候没必要太纠结哪一种方式,其实每种方式之间的效率还是微乎其微的。选择适合自己的就好。为什么parallelStream在数据量较小的时候效率反而不行?这个大家可以在下方留言哦。

总结

上面小实验只是在我机器上跑出来的结果,可能放到不同的机器运行结果有不一样哦,大家感兴趣的同学可以把代码贴到自己的机器上跑一跑,也许我这这个结论就不适用了。

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。

    巨人的肩膀摘苹果:
    https://www.cnkirito.moe/java-jmh/
    https://jmh.morethan.io/

HashMap的循环姿势你真的掌握了吗?的更多相关文章

  1. 【java】TreeMap/HashMap的循环迭代中 keySet和entrySet和forEach方式 + map的几种迭代方式

    参考链接:https://www.cnblogs.com/crazyacking/p/5573528.html ================================== java紫色代表迭 ...

  2. 如果你这么去理解HashMap就会发现它真的很简单

    Java中的HashMap相信大家都不陌生,也是大家编程时最常用的数据结构之一,各种面试题更是恨不得掘地三尺的去问HashMap.HashTable.ConcurrentHashMap,无论面试题多么 ...

  3. HashMap循环遍历方式及其性能对比(zhuan)

    http://www.trinea.cn/android/hashmap-loop-performance/ ********************************************* ...

  4. HashMap循环遍历方式及其性能对比

    主要介绍HashMap的四种循环遍历方式,各种方式的性能测试对比,根据HashMap的源码实现分析性能结果,总结结论.   1. Map的四种遍历方式 下面只是简单介绍各种遍历示例(以HashMap为 ...

  5. HashMap循环

    1. Map的四种遍历方式下面只是简单介绍各种遍历示例(以HashMap为例),各自优劣会在本文后面进行分析给出结论. (1) for each map.entrySet()   Java   1 2 ...

  6. HashMap两种遍历方式的深入研究

    转自:http://swiftlet.net/archives/1259 HashMap的遍历有两种方式,如下所示:第一种利用entrySet的方式:   1 2 3 4 5 6 7 Map map ...

  7. hashMap的get()方法,错用并发造成cpu和负载高

    一次线上问题的解决 线上发现服务cpu使用达到98%,负载高达200多,64核心cpu,下面介绍解决过程: 1.top命令查出占用cpu高的进程pid 2.使用jstack -l pid >du ...

  8. HashMap两种遍历数据的方式

    HashMap的遍历有两种方式,一种是entrySet的方式,另外一种是keySet的方式. 第一种利用entrySet的方式: Map map = new HashMap(); Iterator i ...

  9. JDK1.7中HashMap底层实现原理

    一.数据结构 HashMap中的数据结构是数组+单链表的组合,以键值对(key-value)的形式存储元素的,通过put()和get()方法储存和获取对象. (方块表示Entry对象,横排表示数组ta ...

随机推荐

  1. Spring与Web环境集成

    1. Spring与Web环境集成 1.1 ApplicationContext应用上下文获取方式 应用上下文对象是通过new ClasspathXmlApplicationContext(sprin ...

  2. java45

    Collection c2 = new ArrayList(); c2.add("a"); c2.add("b"); //移除集合中的某个元素 c2.remov ...

  3. 20190814_tomcat配置项目的错误页

    1. 打开项目中的web.xml, 注意不是tomcat的web.xml; 一般是在项目的 WEB-INF目录下, 然后加上下面的语句 <error-page> <error-cod ...

  4. Vue3教程:Vue 3.x 快在哪里?

    人云亦云,并不会让你变得有多优秀,而会让你越来越随大流. 当你和别的开发在聊到 Vue 3.0 版本发布,有哪些亮点时,你的答案之一肯定有"它变得更快了,性能上快了 1.2 - 2倍&quo ...

  5. 第7.14节 Python类中的实例方法详析

    第7.14节 Python类中的实例方法详析 一.    实例方法的定义 在本章前面章节已经介绍了类的实例方法,实例方法的定义有三种方式: 1.    类体中定义实例方法 第一种方式很简单,就是在类体 ...

  6. PyQt(Python+Qt)学习随笔:Qt Designer中部件的是否接受鼠标拖放事件的acceptDrops属性及含义

    acceptDrops属性表示当前部件是否接受鼠标拖放事件,鼠标拖放应该是与鼠标拖拽结合在一起的,在Qt Designer中可以通过属性acceptDrops设置部件是否接受鼠标拖放事件.如果部件接受 ...

  7. neo4j数据库数据转移,从阿里云转移到windows服务器

    1.从阿里云迁移neo4j时需停掉neo4j数据库,在neo4j的bin目录下输入 ./neo4j stop 2.将数据备份到一个文件中 ./neo4j-admin dump --database=g ...

  8. 权威部门接连下发文件,Panda交易所带你走进区块链概念股

    Panda交易所获悉,7月21日,北京市地方金融监督管理局发文<北京股权交易中心获得首批开展区块链试点建设资格>,文中表示证监会7月7日发布<关于原则同意北京.上海.苏州.浙江.深圳 ...

  9. 【题解】P2610 [ZJOI2012]旅游

    link 题意 T国的国土可以用一个凸N边形来表示,包含 \(N-2\) 个城市,每个城市都是顶点为 \(N\) 边形顶点的三角形,两人的旅游路线可以看做是连接N个顶点中不相邻两点的线段.问一路能经过 ...

  10. 【APIO2019】桥梁(询问分块)

    Description 给定一张 \(n\) 个点,\(m\) 条边的无向图,边 \(i\) 的权值为 \(d_i\).现有 \(q\) 次操作,第 \(j\) 个操作有两种模式: \(1\ b_j\ ...