Map的6种遍历方式
keySet()/values()遍历
for-each:一种遍历形式
可以遍历集合或者数组,实际上是迭代器遍历的简化写法,也称增强for循环。
each表示每个;for-each表示循环数组或集合中的对象、数据。
keySet()方法:拿到全部的Key
将Map中所有的键(Key)存入到Set集合中。
Key表示键值;Set表示Set集合。
values()方法:拿到全部的Value
返回一个新的Iterator(迭代器)对象,该对象包含Map中存在的每个元素的值(Value)。
vluees是值的复数形式,表示它有很多的值。
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//for-each + keySet()遍历key
for (String key : map1.keySet()) { //遍历key
System.out.println("key = " + key);
}
//for-each + values()遍历value
for (Integer value : map1.values()) { //遍历value
System.out.println("value = " + value);
}
key = 小明
key = 小红
key = 小张
value = 1
value = 2
value = 3
一次只能取出Key的值或者Value的值,这样显然是很不方便的。
[重要]entrySet()遍历
Map.Entry是为了更方便的输出map键值对。一般情况下,想要输出Map中的key 和 value,就必须先得到key的集合keySet(),然后再循环每个key得到每个value。values()方法是获取集合中的所有值,不包含键,没有对应关系。而Entry可以一次性获得这两个值。
entrySet()方法:拿到全部的键值对
将Map中所有的键(Key)-值(Value)对存入到Set集合中,这个方法返回的是一个Set<Map.Entry<K,V>>。
entry表示条目、清单;Set表示Set集合。
Key1, Value1
Key2, Value2
Key3, Value3
... , ...
Key65535, Value65535
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//for-each + entrySet()遍历
for (Map.Entry<String, Integer> entry : map1.entrySet()) {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
key = 小明, value = 1
key = 小红, value = 2
key = 小张, value = 3
Map.Entry是最常见也最常用的遍历Map的方式
keySet() 遍历
get()方法:传入Key,返回对应的Value
将要返回的元素的键(Key)作为参数,找到并返回对应该键(Key)的值(Value)。
如果没有找到键(Key),返回undefined。
因为键(Key)是唯一的,所以不用担心找到第一个后第二个不输出的问题。
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//for-each + keySet() + get()方法遍历
for (String key : map1.keySet()) {
Integer value = map1.get(key);
System.out.print("key = " + key);
System.out.println(", value = " + value);
}
key = 小明, value = 1
key = 小红, value = 2
key = 小张, value = 3
一般不推荐使用这种方法,因为多了一步根据key查找value的操作,效率会相对慢一些。写法和最开始的for-each遍历很相似,不同的是value使用了get()方法来获取。
map.get(key)方法的底层实现:
先调用Key的Hashcode方法得到哈希值,通过哈希算法得到对应的数组的下标,通过数组下标快速定位到某个位置上,如果这个位置上什么也没有,则返回null,如果这个位置上有单向链表,那么会拿着参数k和单项链表中的每个节点的k进行比较(equals()),如果所有的节点都返回false,那么最终该方法返回null,如果有一个节点的k和我们的k相匹配,那么该k节点所对应的value就是我们要找的value。
Iterator&entrySet()遍历
iterator() 方法:返回一个用于遍历当前集合的迭代器
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//Iterator + entrySet()遍历
Iterator<Map.Entry<String, Integer>> iter = map1.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Integer> entry = iter.next();
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
key = 小明, value = 1
key = 小红, value = 2
key = 小张, value = 3
使用Iterator创建一个迭代器来遍历这个Map,和方法②类似,但区别在于:
for-each通常用于一次性遍历整个集合,大大提升了代码的简洁性和可阅读性,但期间无法控制遍历的过程。而Iterator通过hasNext(),next() 更好地控制便利过程的每一步。
for-each在遍历过程中严禁改变集合的长度,且无法对集合的删除或添加等操作。而Iterator可以在遍历过程中对集合元素进行删除操作。
但是在idea编译器中,编译器会给出警告,提示说该写法可以简化,简化后的写法和for-each + entrySet()方法遍历一致:
for (Map.Entry<String, Integer> entry : map1.entrySet()) {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
[重要]lambda表达式遍历
forEach() 方法:遍历数组中每一个元素并执行特定操作
Lambda表达式:能够非常简练地表达特定的操作行为。在遍历集合中的元素时,如果对每个元素都执行同样的操作,也可以用Lambda表达式来指定对元素的操作行为,从而简化遍历访问集合的代码。
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//lambda表达式遍历
map1.forEach((key, value) -> {
System.out.print("key = " + key);
System.out.println(", value = " + value);
});
key = 小明, value = 1
key = 小红, value = 2
key = 小张, value = 3
forEach方法遍历了map1,同时获取到key和value的值。美观,简洁,大气。
但有最低API版本要求
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
stream流遍历
Stream流的作用:区别于IO流,用来对容器(集合,数组)操作进行书写简化,配合众多函数式接口以及lambda表达式,方法引用,集合的遍历,计数,过滤,映射,截取等操作变得异常优雅,上流。
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//stream流遍历
map1.entrySet().stream().forEach((Map.Entry<String, Integer> entry) -> {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
});
key = 小明, value = 1
key = 小红, value = 2
key = 小张, value = 3
但是在idea编译器中,编译器会给出警告,提示说该写法可以简化,简化后的写法和lambda表达式一致:
map1.forEach((key, value) -> {
System.out.print("key = " + key);
System.out.println(", value = " + value);
});
总结——简洁又好用的遍历方式
①entrySet()遍历
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//for-each + entrySet()遍历
for (Map.Entry<String, Integer> entry : map1.entrySet()) {
System.out.print("key = " + entry.getKey());
System.out.println(", value = " + entry.getValue());
}
②lambda表达式遍历
HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);
//lambda表达式遍历
map1.forEach((key, value)->{
System.out.print("key = " + key);
System.out.println(", value = " + value);
});