一、简述
Java 的 map 遍历有多种方法,如最早的 Iterator,Java5 支持的 foreach,Java8 的 Lambda。HashMap 遍历从大的方向可分为以下 4 类:
- 迭代器(Iterator)方式遍历;
- for each 方式遍历;
- Lambda 表达式遍历(JDK8+);
- Streams API 遍历(JDK8+)。
但每种类型下又有不同的实现方式,因此具体的遍历方式又可分为:
- 使用迭代器(Iterator)EntrySet 的方式进行遍历。
- 使用迭代器(Iterator)KeySet 的方式进行遍历。
- 使用 for each EntrySet 的方式进行遍历。
- 使用 for each KeySet 的方式进行遍历。
- 使用 Lambda 表达式的方式进行遍历。
public class TestMap {
public static Map<String, String> map = new HashMap<String, String>();
map.put("1", "大象");
map.put("2", "猴子");
map.put("3", "老虎");
}
二、entrySet
通过对 map entrySet 的遍历,可以同时拿到 key 和 value。这一般是最常见也是最可取的遍历方式,在键值都需要时使用。一般情况下,性能上要优于方法二。
// entrySet 获取key and value
public void testEntry() {
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
三、keySet values
如果只需要 map 的 key 或者 value,用 map 的 keySet 或 values 方法无疑是最方便的,而不是用 entrySet。
Map<String, String> map = new HashMap<String, String>();
//遍历map中的键
for (String key : map.keySet()) {
System.out.println("Key = " + key);
}
//遍历map中的值
for (String value : map.values()) {
System.out.println("Value = " + value);
}
如果需要同时获取 key 和 value,也可以先获取 key,然后再通过 map 的 get(key) 获取 value。作为方法一的替代,此代码更简洁,但实际上它相当慢且无效率。因为用键取值是耗时的操作(与方法一相比,在不同的 Map 实现中该方法慢了20%~200%)。该方法不是最优选择,一般不推荐使用。
// keySet get(key) 获取key and value
public void testKeySetAndGetKey() {
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
}
四、Iterator
对于上面的几种 foreach 都可以用 Iterator 代替,其实 foreach 在 Java5 中才被支持,foreach 的写法看起来更简洁。
但 Iterator 也有其优势:在用 foreach 遍历 map 时,如果改变其大小,会报错。但如果只是删除元素,可以使用 Iterator 的 remove 方法删除元素,根据 javadoc 的说明,如果在 foreach 遍历中尝试使用此方法,结果是不可预测的。
// Iterator entrySet 获取key and value
//Iterator:业务复杂的可以用while
public void testIterator() {
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println(entry.getKey() + ":" + entry.getValue());
// it.remove(); 删除元素
}
}
//Iterator:普通的可以用foreach遍历
for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();it.hasNext();){
Map.Entry<String,String> entry = it.next();
System.out.println(entry.getKey() + ":" + entry.getValue());
//it.remove(); 会抛java.util.ConcurrentModificationException
}
五、Lambda~流式 map 遍历(Java8)
Java8 提供了 Lambda 表达式支持,语法更简洁,可以同时拿到 key 和 value。不过,经测试性能低于 entrySet,所以更推荐用 entrySet 的方式。
// Lambda 获取key and value
//流式一:
public void testLambda() {
map.forEach((key, value) -> {
System.out.println(key + ":" + value);
});
}
//流式二:Streams API 单线程
map.entrySet().stream().forEach(entry->{
System.out.println("code:"+entry.getKey()+" desc:"+entry.getValue());
});
//流式三:Streams API 多线程
map.entrySet().parallelStream().forEach((entry) -> {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
});
六、小结
- 如果只是获取 key 或 value,推荐使用 keySet 或 values 方式。
- 如果同时需要 key 和 value 推荐使用 entrySet。
- 如果需要在遍历过程中删除元素推荐使用 Iterator。
- 如果需要在遍历过程中增加元素,可以新建一个临时 map 存放新增的元素,等遍历完毕,再把临时 map 放到原来的 map 中。
七、Java 中两个 map 比较
1️⃣用 map 的 keySet() 的迭代器(性能效率较低)
public void compareMap1() {
Map<String, String> m1 = new HashMap<String, String>();//小
Map<String, String> m2 = new HashMap<String, String>();//大
Iterator<String> iter1 = m1.keySet().iterator();
while (iter1.hasNext()) {
String m1Key = iter1.next();
//若两个map中相同key对应的value不相等
if (!m1.get(m1Key).equals(m2.get(m1Key))) {
//......
}
}
}
2️⃣用 map 的 entrySet() 的迭代器(性能效率较高)
public void compareMap2() {
Map<String, String> m1 = new HashMap<String, String>();
Map<String, String> m2 = new HashMap<String, String>();
Iterator<Map.Entry<String, String>> iter1 = m1.entrySet().iterator();
while (iter1.hasNext()) {
Map.Entry<String, String> entry1 = iter1.next();
String m1value = entry1.getValue() == null ? "" : entry1.getValue();
String m2value = m2.get(entry1.getKey()) == null ? "" : m2.get(entry1.getKey());
//若两个map中相同key对应的value不相等
if (!m1value.equals(m2value)) {
//其他操作...
}
}
}
3️⃣用 map 的 entrySet() 的增强型 for 循环(性能效率较高)
public void compareMap3() {
Map<String, String> m1 = new HashMap<String, String>();
Map<String, String> m2 = new HashMap<String, String>();
for (Map.Entry<String, String> entry1 : m1.entrySet()) {
String m1value = entry1.getValue() == null ? "" : entry1.getValue();
String m2value = m2.get(entry1.getKey()) == null ? "" : m2.get(entry1.getKey());
//若两个map中相同key对应的value不相等
if (!m1value.equals(m2value)) {
//其他操作...
}
}
}
网友评论