entrySet()遍历最常用高效,适合键值同时访问;keySet()适合仅操作键或按需获取value;forEach()语法简洁但无法中断;values()仅适用于无需键的场景。

用 entrySet() 遍历最常用也最高效
直接遍历 entrySet() 是 Java 中遍历 HashMap 的首选方式,它避免了重复查表,性能优于先取 key 再 get value 的做法。
- 适用于需要同时访问键和值的场景,比如日志打印、条件过滤、转换成其他结构
-
entrySet()返回的是Set,每个> Map.Entry提供getKey()和getValue()方法 - 注意:不能在遍历过程中直接调用
map.remove(key),否则会抛出ConcurrentModificationException;如需删除,必须用Iterator.remove()
for (Map.Entryentry : map.entrySet()) { System.out.println(entry.getKey() + " = " + entry.getValue()); }
用 keySet() 遍历适合只操作键或需多次 get 的情况
当逻辑主要围绕 key 展开(比如判断是否存在、做 key 的字符串处理),或者你明确知道 value 访问频次很低时,keySet() 更清晰。
- 返回
Set,遍历时通过map.get(key)拿 value,每次调用都是 O(1) 平均复杂度,但有哈希查找开销 - 如果 value 是大对象且不总被用到,这种“按需获取”能节省临时引用
- 注意:若 map 在遍历中被并发修改(非线程安全),同样可能触发
ConcurrentModificationException
for (String key : map.keySet()) {
Integer value = map.get(key); // 显式 get,可空判或加业务逻辑
if (value != null && value > 100) {
System.out.println(key);
}
}
Java 8+ 推荐用 forEach() + Lambda 简化写法
forEach() 是 Map 接口默认方法,底层仍走 entrySet(),语法更紧凑,适合简单遍历逻辑。
- 参数是
BiConsumer super K, ? super V>,即接受 key 和 value 的函数式接口 - 无法在 lambda 中使用
break或continue,也不方便提前退出;如需中断,得改用传统 for 或 Iterator - 若 lambda 体里抛受检异常(如
IOException),需包装或换回 try-catch 块
map.forEach((key, value) -> {
if (value instanceof Integer) {
System.out.printf("%s: %d%n", key, value);
}
});
别用 values() 遍历除非你真不需要 key
values() 返回的是 Collection,它不保证顺序,也不能反查 key —— 这点容易被忽略。
立即学习“Java免费学习笔记(深入)”;
- 仅当业务只要 value 列表(比如统计所有值的总和、找最大值)时才适用
- 如果之后还要根据 value 找 key,不要指望
values().indexOf(...):它不支持,而且values()返回的集合不是随机访问型,indexOf是 O(n) 全扫描 - 对
HashMap来说,values()的迭代顺序和entrySet()一致(基于桶数组顺序),但这属于实现细节,不应依赖
真正要双向映射,该用 Guava 的 BiMap 或自己维护两个 map。









