遍历的"/>
HashMap是如何遍历的
前言
其实用上 JDK1.8 才是近些时日的事,毕竟没有什么新的技术点必须要去用,也懒得去换 JDK 的版本了。这几天在某论坛里看到一个有关于“HashMap如何遍历”的问题,静心一想也就知道那么一两种,于是想了想还是总结总结吧。
遍历方式
大概的总结了一下,HashMap 遍历就是分大概4个方向吧:
- 迭代器(Iterator)方式遍历。
- For Each 方式遍历。
- Lambda 表达式遍历(JDK1.8加入的)。
- Streams API 遍历(JDK1.8加入的)。
大概方向是这么几个,但是遍历方法也不少,一一举例吧。
有的朋友问我怎么我按顺序赋值怎么遍历出来顺序都不对啊,您是不是忘了一件事,Map里面是无序的O(∩_∩)O
(1)用 EntrySet 迭代器
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void entrySetTest() {Iterator<Map.Entry<String, String>> iterator = testMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, String> entry = iterator.next();System.out.println(entry.getKey() + " ------ " + entry.getValue());}}public static void main(String[] args) {Test.entrySetTest();}
}
(2)用 KeySet 迭代器
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void keySetTest() {Iterator<String> iterator = testMap.keySet().iterator();while (iterator.hasNext()) {String key = iterator.next();System.out.println(key + " ------ " + testMap.get(key));}}public static void main(String[] args) {Test.keySetTest();}
}
(3)用 ForEach 处理 EntrySet
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void forEach4EntrySetTest() {for (Map.Entry<String, String> entry : testMap.entrySet()) {System.out.println(entry.getKey() + " ------ " + entry.getValue());}}public static void main(String[] args) {Test.forEach4EntrySetTest();}
}
(4)用 ForEach 处理 KeySet
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void forEach4KeySetTest() {for (String key : testMap.keySet()) {System.out.println(key + " ------ " + testMap.get(key));}}public static void main(String[] args) {Test.forEach4KeySetTest();}
}
(5)用 Lambda
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void lambdaTest() {testMap.forEach((key, value) -> {System.out.println(key + " ------ " + value);});}public static void main(String[] args) {Test.lambdaTest();}
}
(6)用 StreamsAPI 的单线程
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void streamTest() {testMap.entrySet().stream().forEach((entry) -> {System.out.println(entry.getKey() + " ------ " + entry.getValue());});}public static void main(String[] args) {Test.streamTest();}
}
(7)用 StreamsAPI 的多线程
package com.wlee.test;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;public class Test {//定义一个Mappublic static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void parallelStreamTest() {testMap.entrySet().parallelStream().forEach((entry) -> {System.out.println(entry.getKey() + " ------ " + entry.getValue());});}public static void main(String[] args) {Test.parallelStreamTest();}
}
大概是总结了7种遍历方式,当然可能不一定就只有这7种,还需要朋友们多多指教。有时候您会问这些方式都哪些方式更快,性能更好。其实各种遍历方式差别不是很大。
番外篇(性能测试)
Maven 项目请先引入:
<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.20</version><scope>provided</scope>
</dependency>
然后测试类:
package com.wlee.test;import org.openjdk.jmh.annotations.*;
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.concurrent.TimeUnit;@BenchmarkMode(Mode.Throughput) //测试类型:吞吐量
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) //预热2轮,每次1s
@Measurement(iterations = 5, time = 3, timeUnit = TimeUnit.SECONDS) //测试5轮,每次3s
@Fork(1) //fork1个线程
@State(Scope.Thread) //每个测试线程一个实例
public class HashMapTest {public static Map<String, String> testMap = new HashMap() {{for (int i = 0; i < 10; i++) {put("key" + i, "val" + i);}}};public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(HashMapTest.class.getSimpleName()) // 要导入的测试类.output("d:/test/map_test.log") // 输出测试结果的文件.build();new Runner(opt).run(); // 执行测试}@Benchmarkpublic static void entrySetTest() {Iterator<Map.Entry<String, String>> iterator = testMap.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, String> entry = iterator.next();System.out.println(entry.getKey() + " ------ " + entry.getValue());}}@Benchmarkpublic static void keySetTest() {Iterator<String> iterator = testMap.keySet().iterator();while (iterator.hasNext()) {String key = iterator.next();System.out.println(key + " ------ " + testMap.get(key));}}@Benchmarkpublic static void forEach4EntrySetTest() {for (Map.Entry<String, String> entry : testMap.entrySet()) {System.out.println(entry.getKey() + " ------ " + entry.getValue());}}@Benchmarkpublic static void forEach4KeySetTest() {for (String key : testMap.keySet()) {System.out.println(key + " ------ " + testMap.get(key));}}@Benchmarkpublic static void lambdaTest() {testMap.forEach((key, value) -> {System.out.println(key + " ------ " + value);});}@Benchmarkpublic static void streamTest() {testMap.entrySet().stream().forEach((entry) -> {System.out.println(entry.getKey() + " ------ " + entry.getValue());});}@Benchmarkpublic static void parallelStreamTest() {testMap.entrySet().parallelStream().forEach((entry) -> {System.out.println(entry.getKey() + " ------ " + entry.getValue());});}
}
JMH(Java Microbenchmark Harness,JAVA 微基准测试套件)是 Oracle 官方提供的性能测试工具。
测试结束从 log 日志文件中获取相关的信息片段:
Benchmark Mode Cnt Score Error Units
HashMapTest.entrySetTest thrpt 5 2.725 ± 0.319 ops/ms
HashMapTest.forEach4EntrySetTest thrpt 5 2.947 ± 0.416 ops/ms
HashMapTest.forEach4KeySetTest thrpt 5 2.914 ± 0.701 ops/ms
HashMapTest.keySetTest thrpt 5 2.799 ± 0.294 ops/ms
HashMapTest.lambdaTest thrpt 5 2.850 ± 0.455 ops/ms
HashMapTest.parallelStreamTest thrpt 5 2.420 ± 0.581 ops/ms
HashMapTest.streamTest thrpt 5 2.811 ± 0.390 ops/ms
其中 Score 列表示平均执行时间, ± 符号表示误差。从测试结果可以看出有快有慢,其实各种遍历方法在性能方面差别不是很大。
以上测试可能存在误差,毕竟每天机器的配置环境什么都不太一样,仅供参考
结语
其实以上主要是为了分享几种遍历 HashMap 的方式,具体性能测试,甚至安全测试不是主要内容。而且测试代码作者也是参考网络上的文章。
更多推荐
HashMap是如何遍历的
发布评论