keySet()遍历时直接remove会抛ConcurrentModificationException;values()不支持值找键且contains()为O(n);entrySet()最通用高效,支持setValue但不支持结构修改;遍历顺序取决于Map实现类。

keySet() 遍历时修改Map会抛ConcurrentModificationException
直接用 for (K key : map.keySet()) 遍历的同时调用 map.remove(key),几乎必触发 ConcurrentModificationException。这是因为 keySet() 返回的是底层 HashMap 的“弱一致性视图”,迭代器不支持边遍历边结构性修改。
- 安全删除方式:改用
Iterator的remove()方法 - 若需过滤后批量删除,先收集待删 key 到
ArrayList,再统一map.keySet().removeAll(keysToRemove) -
keySet()遍历适合只读场景;如需边查边删,优先考虑entrySet()
values() 不支持通过迭代器反向定位 key
values() 返回的是值的集合视图(Collection),它不保留 key 与 value 的映射关系。这意味着你无法从某个 v 反推出它对应的 k,除非遍历整个 Map 或额外维护反向索引。
- 常见误用:在
for (V v : map.values())中试图调用map.getKey(v)——Map接口根本没有这个方法 - 若业务依赖“值找键”,应改用
entrySet()并手动比对entry.getValue() -
values()的contains()是 O(n) 时间复杂度,非 O(1),别误以为和HashSet一样快
entrySet() 是最通用且性能最优的遍历方式
绝大多数需要同时访问 key 和 value 的场景,都该优先用 entrySet()。它避免了重复哈希查找,也规避了 keySet() + get() 的双重开销。
for (Map.Entryentry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); // 直接操作,无需 map.get(key) }
- Java 8+ 可配合 lambda:
map.forEach((k, v) -> System.out.println(k + "=" + v)) - 若需修改 value,直接调用
entry.setValue(newVal)是合法且高效的 - 注意:
entrySet()迭代器同样不支持结构修改(如map.remove()),但支持entry.setValue()
遍历顺序取决于具体 Map 实现类
HashMap 的 keySet()、values()、entrySet() 都不保证顺序;LinkedHashMap 按插入顺序;TreeMap 按 key 自然序或自定义比较器排序。
立即学习“Java免费学习笔记(深入)”;
- 不要假设
HashMap.values()的顺序和keySet()一致——虽然通常“碰巧”一致,但这不是规范保证 - 需要稳定顺序时,显式选择
LinkedHashMap或TreeMap,而非依赖HashMap的内部实现细节 - 多线程环境下,即使用了
ConcurrentHashMap,其keySet()迭代结果仍是弱一致性快照,不能当作实时全量视图










