forEach是Stream的终端消费操作,不返回流、不保证并行流顺序、不可链式调用,适用于打印或修改外部状态等副作用;需用forEachOrdered保序,禁止遍历中修改集合,也不适合收集结果或提前终止。

Java 中 forEach 是 Stream 的终端操作,用于对流中每个元素执行指定动作,但它不返回新流,也不能链式调用后续 Stream 操作;它本质是“消费”元素,适合做打印、记录、修改外部状态等副作用操作。
forEach 基本用法
接收一个 Consumer<T> 函数式接口,常见写法有三种:
- 使用 Lambda 表达式:
list.stream().forEach(x -> System.out.println(x)); - 使用方法引用:
list.stream().forEach(System.out::println); - 使用匿名内部类(少用):
stream.forEach(new Consumer<String>() { public void accept(String s) { ... } });
注意:forEach 不保证遍历顺序
对于**并行流(parallelStream)**,forEach 的执行顺序是不确定的。如果需要按插入顺序处理,应改用 forEachOrdered:
-
list.parallelStream().forEach(x -> ...)→ 顺序不保证 -
list.parallelStream().forEachOrdered(x -> ...)→ 保持原始顺序,但可能牺牲并行性能
不能在 forEach 中修改集合本身
遍历过程中直接调用 list.remove() 或 add() 会触发 ConcurrentModificationException(即使不是多线程)。正确做法是:
立即学习“Java免费学习笔记(深入)”;
- 收集待删除元素,遍历完再批量移除:
list.removeIf(x -> x.startsWith("A")); - 用迭代器安全删除:
Iterator<String> it = list.iterator(); while (it.hasNext()) { if (...) it.remove(); } - 用
stream().filter().collect(Collectors.toList())构建新集合
forEach 不适合“收集结果”或“提前终止”
它没有返回值,也无法像 anyMatch 或 findFirst 那样短路。如果目标是:
- 找某个元素 → 用
findAny()或findFirst() - 判断是否存在 → 用
anyMatch() - 转成新集合 → 用
map().collect(...) - 求和/统计 → 用
reduce()或sum()等聚合方法
不复杂但容易忽略:它只是“逐个执行动作”,别指望它帮你做转换或终止控制。


















