最推荐 Map 遍历方式是 entrySet() + 增强 for 或 forEach(),性能优、代码简洁、支持安全删除和值修改;keySet() + get() 因重复哈希查找而低效,仅适用于纯 key 场景或小数据量。

Map 遍历最常用、最推荐的方式是 entrySet() + 增强 for 循环或 forEach(),性能好、代码干净、支持安全修改;而仅用 keySet() + get() 的方式,看似简单,实际在大数据量下会多一次哈希查找,属于典型“看着对、跑得慢”的写法。
entrySet() 是默认首选:一次拿到 key 和 value
这是 Java 中遍历 Map 最高效也最通用的方式。它直接返回 Set,每个 Map.Entry 对象天然封装了键和值,无需二次查表。
- 避免重复哈希计算:相比
keySet()方式,节省约 50% 的寻址开销 - 支持遍历时安全删除:调用
entry.remove()不会抛ConcurrentModificationException - 支持直接修改值:
entry.setValue(newVal)比map.put(key, newVal)更轻量
Mapmap = new HashMap<>(); map.put("a", 1); map.put("b", 2); for (Map.Entry entry : map.entrySet()) { System.out.println(entry.getKey() + " → " + entry.getValue()); }
forEach() + Lambda:JDK 8+ 的简洁写法
Map.forEach() 底层就是基于 entrySet() 实现的,语法更紧凑,适合只读遍历场景。
- 要求 JDK ≥ 8,不兼容老版本(如 Android API 23 及以下需注意)
- 不能在 lambda 里 break/continue,也不支持 throw 受检异常
- 若需过滤或转换,应改用
stream(),而非硬塞逻辑进forEach
map.forEach((key, value) -> {
if (value > 1) {
System.out.println(key + " is large");
}
});
keySet() 遍历:只适合“真只需要 key”或小数据量
用 map.keySet() 再逐个 map.get(key) 是新手常见写法,但它是性能陷阱——每次 get() 都要重新计算哈希、定位桶、处理冲突链。
- 当 Map 是
ConcurrentHashMap时,get()还可能触发额外的 volatile 读 - 无法在遍历中安全删除元素(
iterator.remove()可以,但map.remove(key)会报错) - 如果业务只要 key(比如做权限校验、日志打点),那它反而更清晰
for (String key : map.keySet()) {
// ✅ 合理:只关心 key
log.info("Processing key: {}", key);
// ❌ 低效:又去 get 一次 value
Integer val = map.get(key); // 多一次哈希查找!
}
values() 和 stream():用前先想清楚代价
map.values() 只返回 Collection,完全丢弃 key —— 如果后续还要反查 key,就掉坑里了;stream() 看似现代,但 map.entrySet().stream() 会额外创建 Stream 对象和中间操作节点,纯遍历毫无优势。
立即学习“Java免费学习笔记(深入)”;
-
values()适合统计、聚合等只依赖 value 的场景(如求最大值、平均分) -
stream()仅在需要 filter/map/collect 等链式操作时才值得用,否则就是杀鸡用牛刀 - 所有 Stream 操作默认是串行的,没加
parallelStream()就别幻想并发加速
forEach(),如果里面嵌套了 map.get(),照样退化成 keySet() 级别的低效。










