一.创建Map
遍历需要先创建一个测试类,这个测试类我们简单的写成如下
HashMap<String,String> map = new HashMap<>(); map.put("key1","value1"); map.put("key2","value2"); map.put("key3","value3"); map.put("key4","value4");
二.遍历Map
方式一:使用entrySet遍历(推荐使用)
遍历方式如下:这里可以选择使用for循环、增强for循环、do-while循环、lamdba表达式等方式对EntrySet实现遍历,这些本质上都是遍历entrySet的不同方式而已,都属于同一种方式遍历,这里只展示使用lamdba的遍历方式。
Set<Map.Entry<String,String>> set = map.entrySet(); set.stream().forEach(entry ->{ System.out.println(entry.getKey()+":"+entry.getValue()); });
方式二:使用keySet遍历
这里也可以选择使用for循环、增强for循环、do-while循环、lamdba表达式等方式对KeySet实现遍历,这些本质上都是遍历keySet的同一种方式遍历,这里只展示使用lamdba的遍历方式。
Set<String> set2 = map.keySet(); set2.stream().forEach(key ->{ System.out.println(key+":"+map.get(key)); });
方式三:使用entrySet+Iterator遍历
这种方式需要使用entrySet方法加上迭代器,代码如下:
Iterator<Map.Entry<String,String>> iterable = map.entrySet().iterator(); while(iterable.hasNext()){ Map.Entry<String,String> entry = iterable.next(); System.out.println(entry.getKey()+":"+entry.getValue()); }
方式四:使用keySet+Iterator遍历
这种方式需要使用keySet方法加上迭代器,代码如下:
Iterator<String> set3 = map.keySet().iterator(); while(set3.hasNext()){ String key = set3.next(); System.out.println(key+":"+map.get(key)); }
方式五:使用keySet、values方法遍历
这种方式是key和value分别遍历的形式,应用场景不多,但也是一种方式,且效率不高,不推荐使用
Set<String> set4 = map.keySet(); set4.stream().forEach(key ->{ System.out.println(key); }); Collection<String> values = map.values(); values.stream().forEach(value ->{ System.out.println(value); });
方式六:使用JDK8提供的forEach方法遍历(推荐使用)
forEach方法是JDK8提供的方法,是为了我们方便使用lamdba。这个方法使用lamdba来实现,是非常简洁的。需要传入一个BiConsumer<K,U>,k和u其实就是键和值,我们只需要传入然后操作即可,代码如下:
map.forEach((key,value) ->{ System.out.println(key+":"+value); });
三.总结
六种方式我们不可能都用到,肯定还是需要选取效率最高的来使用,那哪种效率最高呢,来实际测试下。
1.测试六种遍历的效率
笔者往HashMap中插入了100万个数据,然后测试了这六种不同遍历方式所需要的时间如,且每个方式都经过了多次测试,得出数据如下(单位:毫秒):
//数组长度值的来源:1000000/0.75+1=1333334 HashMap<String,String> hashMap = new HashMap<>(1333334); 方式一:3500-4000之间 方式二:3500-4000之间 方式三:3000-3600之间 方式四:3500-4000之间 方式五:6000-7000之间 方式六:3500-4000之间
可以发现除了key、value分别遍历的场景耗时比较严重,其他没有什么差别,显然这个结果是不对的,那是什么原因影响了正常结果呢,显然不可能是数据量不够,那么就只可能是即时编译器的锅了,我们知道即时编译器会对代码优化以及指令重排,这会影响到我们的正常程序逻辑。下面笔者禁用了即时编译器又重新测试了下。
2.禁用即时编译器,重新测试遍历的效率
首先我们禁用即时编译器,如下:
然后再一次测试各个遍历方式所消耗的时间,这里展示第一种遍历耗费时间的截图:
经过多次测试,六种遍历方式所耗时间如下:
方式一:稳定在8100左右 方式二:稳定在9900左右 方式三:稳定在8900左右 方式四:稳定在12000左右 方式五:稳定在12000左右 方式六:稳定在8300左右
上面所示就是六种遍历HashMap的效率了,可以清晰的看到哪个遍历效率才是最高的,排除微弱因素影响,我们使用方式一和方式六肯定是最好的选择。下面根据效率队各种遍历进行一个排序。
方式六(使用forEach方法) 等价于 方式一(使用entrySet方法) 优于 方式三(使用entrySet方法+Iterator迭代器) 优于 方式二(使用keySet方法) 优于 方式四(使用keySet方法+Iterator迭代器) 优于 方式五(使用keySet、values方法,分别遍历key、value)
3.该如何选择HashMap的遍历方式
根据上面的测试结果,可以很清晰的看到,我们在开发中应该首选forEach方法进行对HashMap进行遍历,使用entrySet方法也是可以的,但是不要使用keySet对Map进行遍历,所有涉及keySet的遍历方式效率均不高。阿里的开发手册中也是明令禁止使用keySet方法对HashMap进行遍历的。这里对HashMap的遍历总结就完了,希望这个总结也可以帮到路过的你。