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

用 entrySet() 遍历最常用也最高效
直接遍历 entrySet() 是 Java 中遍历 HashMap 的首选方式,它返回的是 Set<map.entry>></map.entry>,每个元素都包含键和值,避免了重复查表开销。
- 比分别调用
keySet()再逐个get()快一倍左右(尤其在大 Map 时) - 支持在循环中安全修改值(但不能删 key,否则抛
ConcurrentModificationException) - 泛型清晰,编译期就能检查类型
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
for (Map.Entry<String, Integer> 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<Map.Entry<String, Integer>> iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, Integer> entry = iter.next();
if (entry.getValue() == 1) {
iter.remove(); // 安全删除
}
}
遍历本身不难,真正容易出问题的是混用不同遍历方式、在循环里误删元素、或忽略 null 值语义——这些地方一旦出错,往往表现为偶发的 NullPointerException 或 ConcurrentModificationException,调试起来反而比写逻辑花更长时间。










