entrySet()遍历最常用且高效,直接获取键值对避免重复查表,性能优于keySet()和forEach();唯一安全删除方式是Iterator.remove()。

用 entrySet() 遍历最常用也最高效
直接遍历 entrySet() 是 Java 中遍历 HashMap 的首选方式,它返回的是 Set,每个元素都包含键和值,避免了重复查表开销。
- 比分别调用
keySet()再逐个get()快一倍左右(尤其在大 Map 时) - 支持在循环中安全修改值(但不能删 key,否则抛
ConcurrentModificationException) - 泛型清晰,编译期就能检查类型
Mapmap = new HashMap<>(); map.put("a", 1); map.put("b", 2); for (Map.Entry entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + " -> " + value); }
遍历 keySet() 适合只关心键或需复用 key 的场景
如果逻辑只需要键,或者后续还要用这个键做其他操作(比如查另一个 Map),keySet() 更轻量。但它每次取值都要走一次哈希查找,性能不如 entrySet()。
- 适用于「先过滤键,再处理对应值」的流程
- 注意:若键为
null,get(null)返回null,但无法区分是没找到还是值本身就是null - 迭代器行为与
entrySet()一致,同样不支持边遍历边remove()(除非用Iterator.remove())
for (String key : map.keySet()) {
Integer value = map.get(key); // 多一次 hash 查找
if (value != null && value > 0) {
System.out.println(key);
}
}
用 forEach() + Lambda 要小心空指针和并发修改
Java 8 引入的 forEach() 看起来简洁,但底层仍基于 entrySet().iterator(),语义上等价于增强 for 循环,**不是并行操作**。
- 参数是
BiConsumer super K, ? super V>,第一个是 key,第二个是 value - 如果 value 可能为
null,Lambda 体内要主动判空,否则可能触发NullPointerException - 在遍历过程中调用
map.put()或map.remove()会立即抛出ConcurrentModificationException
map.forEach((key, value) -> {
if (value != null) {
System.out.println(key + "=" + value);
}
});
Iterator.remove() 是唯一安全的遍历中删除方式
想在遍历过程中删掉某些键值对?别用 map.remove(key),必须用迭代器自己的 remove() 方法,否则一定报错。
立即学习“Java免费学习笔记(深入)”;
-
entrySet().iterator()和keySet().iterator()都提供remove() - 每调用一次
next()后最多只能调用一次remove(),重复调用抛IllegalStateException - 删除后当前 entry 不再有效,但不影响后续迭代
Iterator遍历本身不难,真正容易出问题的是混用不同遍历方式、在循环里误删元素、或忽略> iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); if (entry.getValue() == 1) { iter.remove(); // 安全删除 } }
null 值语义——这些地方一旦出错,往往表现为偶发的 NullPointerException 或 ConcurrentModificationException,调试起来反而比写逻辑花更长时间。










