当前位置: 首页 > 科技观察

你真的正确使用HashMap的循环姿势吗?

时间:2023-03-18 15:29:04 科技观察

hashMap应该是java程序员在工作中使用较多的一种键值对处理的数据类型。hashMap有六七种常见的遍历方法。这么多选择,你一般会用哪一个来遍历数据列呢?欢迎在下方留言。说实话,方法太多了,想记也记不住,也不想浪费时间去记,所以在JDK1之前基本都是用Map.Entry来遍历。我用过forEach,但是这个不能有continue或者break操作,有时候很不方便。其他类型我用的不多,对这些方法也没有过多研究。哪一个性能更好。总之,选择自己熟悉的方式就好了。好了废话不多说,直接进入今天的主题。先来看看各个遍历方法:在for循环中使用entries实现Map遍历publicstaticvoidforEachEntries(){for(Map.Entryentry:map.entrySet()){StringmapKey=entry.getKey();StringmapValue=entry.getValue();}}在for循环中遍历键publicstaticvoidforEachKey(){for(Stringkey:map.keySet()){StringmapKey=key;StringmapValue=map.get(mapKey);}}在一个for循环中遍历值.entrySet().iterator();while(entries.hasNext()){Entryentry=entries.next();Stringkey=entry.getKey();Stringvalue=entry.getValue();}}forEachjdk1.8遍历publicstaticvoidforEach(){map.forEach((key,val)->{Stringkey1=key;Stringvalue=val;});}streamjdk1.8遍历map.entrySet().stream().forEach((entry)->{Stringkey=entry.getKey();Stringvalue=entry.getValue();});Streamparalleljdk1.8traversalpublicstaticvoidforEachStreamparallel(){map.entrySet().parallelStream()。forEach((entry)->{Stringkey=entry.getKey();Stringvalue=entry.getValue();});}以上是一些常用的map遍历方式。我们来写一个测试用例,看看这几种遍历方式哪种最高效?以下测试用例基于JMH进行测试。首先引入pomorg.openjdk.jmhjmh-core1.23org.openjdk.jmhjmh-generator-annprocess1.23provided一些可能影响jmh测试结果的因素会这里不做详细介绍。您可以参考文章末尾的第一个链接以获得非常详细的描述。以及测试用例为什么要这样写(都是为了消除JIT对测试代码的影响)。这是官网链接:编写测试代码如下:jmh.results.format.ResultFormatType;importorg.openjdk.jmh.runner.Runner;importorg.openjdk.jmh.runner.RunnerException;importorg.openjdk.jmh.runner.options.Options;importorg.openjdk.jmh.runner.options。OptionsBuilder;importjava.util.HashMap;importjava.util.Iterator;importjava.util.Map;importjava.util.Map.Entry;importjava.util.UUID;importjava.util.concurrent.TimeUnit;/***@author:公众号:javafinance*@Date:*@Description:微信搜索【javafinance】回复666*/@State(Scope.Thread)@Warmup(iterations=5,time=1,timeUnit=TimeUnit.SECONDS)@Measurement(迭代次数=5,时间=1,timeUnit=TimeUnit.SECONDS)@Fork(1)@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.NANOSECONDS)publicclassInstructionsBenchmark{publicstaticvoidmain(String[]args)throwsRunnerException{Optionsopt=newOptionsBuilder().include(InstructionsBenchmark.class.getSimpleName()).result("result.json").resultFormat(ResultFormatType.JSON).build();newRunner(opt).run();}staticfinalintBASE=42;staticintadd(intkey,intval){returnBASE+key+val;}@Param({"1","10","100","1000","10000","100000"})intsize;privatestaticMapmap;//初始化方法,在运行所有Benchmarks之前执行@Setup(Level.Trial)publicvoidinit(){map=newHashMap<>(size);for(inti=0;ientry:map.entrySet()){IntegermapKey=entry.getKey();IntegermapValue=entry.getValue();blackhole.consume(add(mapKey,mapValue));}}/***for循环遍历key*/@BenchmarkpublicstaticStringBufferforEachKey(Blackholeblackhole){StringBufferstringBuffer=newStringBuffer();for(Integerkey:map.keySet()){//IntegermapValue=map.get(key);blackhole.consume(add(key,key));}returnstringBuffer;}/***在for循环中遍历value*/@BenchmarkpublicstaticvoidforEachValues(Blackholeblackhole){for(Integerkey:map.values()){blackhole.consume(add(key,key));}}/***Iterator遍历;*/@BenchmarkpublicstaticvoidforEachIterator(Blackholeblackhole){Iterator>entries=map.entrySet().iterator();while(entries.hasNext()){Entryentry=entries.next();Integerkey=entry.getKey();Integervalue=entry.getValue();blackhole.consume(add(key,value));}}/***forEachjdk1.8历*/@BenchmarkpublicstaticvoidforEachLamada(Blackholeblackhole){map.forEach((key,value)->{blackhole.consume(add(key,value));});}/***forEachjdk1.8历*/@BenchmarkpublicstaticvoidforEachStream(Blackholeblackhole){map.entrySet().stream().forEach((entry)->{Integerkey=entry.getKey();Integervalue=entry.getValue();blackhole.consume(add(key,value));});}@BenchmarkpublicstaticvoidforEachStreamparallel(Blackholeblackhole){map.entrySet().parallelStream().forEach((entry)->{Integerkey=entry.getKey();Integervalue=entry.getValue();blackhole.consume(add(key,value));});}}结果如下如下:》注:运行环境idea2019.3,jdk1.8,windows764位」Benchmark(size)ModeCntScoreErrorUnitsInstructionsBenchmark.forEachEntries1avgt510.021±0.224ns/opInstructionsBenchmark.forEachEntries10avgt571.709±2.537ns/opInstructionsBenchmark.forEachEntries100avgt5738.873±12.132ns/opInstructionsBenchmark.forEachEntries1000avgt57804.431±136.635ns/opInstructionsBenchmark.forEachEntries10000avgt588540.345±14915.682ns/opInstructionsBenchmark.forEachEntries100000avgt51083347.001±136865.960ns/opInstructionsBenchmark.forEachIterator1avgt510.675±2.532ns/opInstructionsBenchmark.forEachIterator10avgt573.934±4.517ns/opInstructionsBenchmark.forEachIterator100avgt5775.847±198.806ns/opInstructionsBenchmark.forEachIterator1000avgt58905.041±1294.618ns/opInstructionsBenchmark.forEachIterator10000avgt598686.478±10944.570ns/opInstructionsBenchmark.forEachIterator100000avgt51045309.216±36957.608ns/opInstructionsBenchmark.forEachKey1avgt518.478±1.344ns/opInstructionsBenchmark.forEachKey10avgt576.398±12.179ns/opInstructionsBenchmark.forEachKey100avgt5768.507±23.892ns/opInstructionsBenchmark.forEachKey1000avgt511117.896±1665.021ns/opInstructionsBenchmark.forEachKey10000avgt584871.880±12056.592ns/opInstructionsBenchmark.forEachKey100000avgt51114948.566±65582.709ns/opInstructionsBenchmark.forEachLamada1avgt59.444±0.607ns/opInstructionsBenchmark.forEachLamada10avgt576.125±5.640ns/opInstructionsBenchmark.forEachLamada100avgt5861.601±98.045ns/opInstructionsBenchmark.forEachLamada1000avgt57769.714±1663.914ns/opInstructionsBenchmark.forEachLamada10000avgt573250.238±6032.161ns/opInstructionsBenchmark.forEachLamada100000avgt5836781.987±72125.745ns/opInstructionsBenchmark.forEachStream1avgt529.113±3.275ns/opInstructionsBenchmark.forEachStream10avgt5117.951±13.755ns/opInstructionsBenchmark.forEachStream100avgt51064.767±66.869ns/opInstructionsBenchmark.forEachStream1000avgt59969.549±342.483ns/opInstructionsBenchmark.forEachStream10000avgt593154.061±7638.122ns/opInstructionsBenchmark.forEachStream100000avgt51113961.590±218662.668ns/opInstructionsBenchmark.forEachStreamparallel1avgt565.466±5.519ns/opInstructionsBenchmark.forEachStreamparallel10avgt52298.999±721.455ns/opInstructionsBenchmark.forEachStreamparallel100avgt58270.759±1801.082ns/opInstructionsBenchmark.forEachStreamparallel1000avgt516049.564±1972.856ns/opInstructionsBenchmark.forEachStreamparallel10000avgt569230.849±12169.260ns/opInstructionsBenchmark.forEachStreamparallel100000avgt5638129.559±14885.962ns/opInstructionsBenchmark.forEachValues1avgt59.743±2.770ns/opInstructionsBenchmark.forEachValues10avgt570.761±16.574ns/opInstructionsBenchmark.forEachValues100avgt5745.069±329.548ns/opInstructionsBenchmark.forEachValues1000avgt57772.584±1702.295ns/opInstructionsBenchmark.forEachValues10000avgt574063.468±23752.678ns/opInstructionsBenchmark.forEachValues100000avgt5994057.370±279310.867ns/op通过上述的图我们可以发现,数据量较小的时候forEachEntries和forEachIterator、以及lamada循环效率他们几乎是一样的。forEachStreamarallel的效率较低。只有当数据量达到10000以上时,parallelStream的优势才体现出来。因此,在选择使用哪种循环方式时,无需过于纠结于使用哪种方式。事实上,每个方法之间的效率仍然可以忽略不计。只需选择适合您的即可。为什么parallelStream在数据量小的时候效率不高?您可以在下方留言。综上所述,上面的小实验只是在我的机器上运行的结果。在不同的机器上结果可能不同。有兴趣的可以把代码贴在自己的机器上运行一下。也许我有这个结论。不适用。本文转载自微信公众号「java财经」,可通过以下二维码关注。转载本文请联系java财经公众号。