接手一个老项目,里面遍历 HashMap 用的还是 Iterator 配 while,二十多行就为了打印个 key 和 value。我顺手改成 forEach,一行就搞定了,同事还问我这是什么新语法。
Java 8 之前的老写法
以前遍历 Map 得先拿 entrySet,再用增强 for 循环:
Map<String, Integer> m = new HashMap<>();
for (Map.Entry<String, Integer> e : m.entrySet()) {
System.out.println(e.getKey() + e.getValue());
}这种写法啰嗦,但好处是随时能 break 和 continue。要在循环里删元素,得走 Iterator 的 remove,直接调 map.remove 会抛 ConcurrentModificationException。
Java 8 的 forEach 一行搞定
Map 自带了 forEach 方法,传一个接收 key 和 value 的 Lambda:
m.forEach((k, v) -> System.out.println(k + v));读起来直观,适合只读操作。想并行就把流打开,m.entrySet().parallelStream().forEach 也行,不过并行下输出顺序是乱的,别指望它按插入顺序打印。
三种取值的代价不一样
- entrySet:一次拿键值对,最省,推荐默认用它
- keySet 再 get:每次 get 都要再哈希一次,数据量大时慢一截
- values:只要值不要键时用,省得解包
遍历时改 Map 会炸
不管哪种写法,遍历过程中直接 put 或 remove 都会触发 fail-fast。真要在遍历里过滤,用 entrySet 的 removeIf,或者先把要删的 key 收集到另一个 List,循环结束再统一删。TreeMap 按键排序,LinkedHashMap 按插入顺序,选错实现,遍历出来的顺序就和你想的不一样。
日常写只读逻辑直接 forEach,需要中途跳出或者删元素就退回 entrySet 加 for,这是我现在的习惯分界。