一、for循环 + KeySet(效率低)/values

分别遍历 key 和 values

通过map.keySet()方法可以获取Map的所有key的集合(set)。然后通过遍历这个Set就可以遍历到Map的key,如果想要同时遍历到Map的value,则需要进一步通过key来从Map这个集合中获取对应的value。【不推荐,只能获取key或value,要想获取对应的value和key,需要重复计算

for(String key:map.keySet()){
   System.out.println(key);
}

for(String value:map.values()){
   System.out.println(value);
}

二、get方法获取;Iterator + Keyset(效率低)

通过Set<K> keySet() 方法获取Map集合所有的key,然后通过key获取value

Set<String> keySet = map.keySet();
for (String key:keySet){
   System.out.println(key + ":" + map.get(key));
}

或

Set set = map.keySet();
Iterator<String> it = set.iterator();
while (it.hasNext()){
   String key = it.next();
   System.out.println("Key:" + key + ";" + "Value:" + map.get(key));
}

相对来说通过Set<K> keySet() 方法效率更低,获取Map集合所有的key,然后通过key获取value,需要遍历Key获取值,本身就耗时 

注:

根据阿里开发手册,也不建议使用这种方法,因为会迭代两次。keySet获取Iterator一次,还要通过get又迭代一次,降低性能

三、Entryset

for循环 + Entryset;Iterator迭代器迭代 + Entryset

for(Map.Entry<Integer,String> entry : map.entrySet()){
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
}

首先通过map.entrySet()方法,可以获取到一个Set集合,这个集合中的每一个元素就是Map中的一个键值对。然后通过循环遍历这个Set集合,可以依次取出每对的键和值。该方法使用了foreach循环,代码简洁明了,且能获取Map的键和值,是最常见且多数情况最可取的遍历方式

注:for-each循环在java 5中被引入。所以该方法只能应用于java 5及以上版本。如果遍历Map是null,for-each循环将抛出NullPointerException,因此在遍历前需要检查空引用

通过Set<Map.Entry<K,V>> entrySet()方法获取泛型对象为 Map.Entry<K,V> 的Set集合,然后使用Iterator迭代器遍历,每次取出 Map.Entry<K,V> 对象的 key和value

Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
while(entries.hasNext()){
    Map.Entry<String, String> entry = entries.next();
    String key = entry.getKey();
    String value = entry.getValue();
    System.out.println(key+":"+value);
}

Entry是Map接口的内部接口,获取迭代器,然后循环依次取出每个迭代器里面的Entry,再通过Entry取出每个键值对。该种方法看起来冗余,却是老版本java中遍历map的唯一方式。第一种遍历方法其实是这种方法通过语法糖做的一种编码方式,其本质是一样的。所以在性能方面,两种方法基本相同。另外,如果在遍历过程中,有删除某些键值对的需求,需要使用这种遍历方式

四、Java8中Map接口中默认Lambda表达式

从Java8开始,Java提供了对Lambda表达式的支持,通过Lambda表达式可以使代码更简洁,这其中就包括用Lambda表达式实现遍历Map的功能

/**
*
* default void forEach(BiConsumer<? super K, ? super V> action)
* BiConsumer 接口中方法:
* void accept(T t, U u); 对给定的参数执行操作
*/
map.forEach((key,value) -> {
    System.out.println(key + ":" + value);
});

Lambda表达式的forEach方法,其实就是一种语法糖,可以让代码更加简洁,使用更加方便。查看源码,我们可以发现,这种方式也是对entrySet遍历方式的一种包装

五、Stream流

map.entrySet().stream().forEach((Map.Entry<Integer, String> entry) -> {
    System.out.println(entry.getKey());
    System.out.println(entry.getValue());
});

总结:

1、EntrySet的方式比KeySet性能要好,原因在于keySet相当于遍历了2次

2、单纯的获取key来说,两者的差别并不大,但是如果要获取value,还是entrySet的效率会更好,因为keySet需要从map中再次根据key获取value,而entrySet一次都全部获取出来

map.get(key)是计算密集型操作,很耗费CPU

3、EntrySet的Iterator遍历的效率比for循环效率更好

4、lambda 表达式和Entryset的底层原理相同,且语法更加简洁。

结论:JAVA8以下推荐使用方法三,即for循环 + Entryset;Iterator迭代器迭代 + Entryset

JAVA8及以上,推荐使用方法四、五,即Lambda表达式和Stream

注:

foreach的语法只是对iterator进行了简单的包装,使用起来更加方便而已,但是如果在foreach循环体内,对集合元素进行删除添加操作的时候,会报出ConcurrentModificationException,并报修改异常。如果需要在遍历集合的时候对象集合中元素进行删除操作,需要使用iterator的遍历方式,iterator自带的remove删除方式不会报出异常

JAVA遍历Map的几种方法_java map遍历的几种方式_老鼠只爱大米的博客-CSDN博客