中间操作返回Stream并惰性执行,终止操作返回非Stream类型并触发实际计算。中间操作如filter、map可链式调用,终止操作如collect、forEach执行后流不可复用,同一Stream只能消费一次。

区分中间操作和终止操作,关键就看两点:返回值类型和是否真正触发执行。
看返回值是不是 Stream
中间操作一定返回 Stream<T>,比如 filter、map、sorted、distinct、limit、skip、flatMap —— 它们都能继续接其他操作,形成链式调用。
终止操作返回的一定是非 Stream 类型,比如 List、Long、Boolean、Optional、void 或自定义对象。像 collect、forEach、count、findFirst、anyMatch、reduce、toArray 都属于这一类。一旦调用,流就“用完了”,不能再复用。
看有没有实际执行数据处理
中间操作是惰性的,只记录要做什么,不碰数据。写完 stream.filter(x -> x > 0).map(String::valueOf),什么都没发生。
立即学习“Java免费学习笔记(深入)”;
只有加上终止操作,比如 .collect(Collectors.toList()) 或 .forEach(System.out::println),整条流水线才从头开始跑,filter 和 map 才真正逐个处理元素。
- 没终止操作 → 代码白写,控制台没输出,集合没变化
- 有终止操作 → 所有前面的中间操作一次性执行
同一个 Stream 只能消费一次
Stream 是一次性资源。执行过一次 forEach 或 collect 后,再调用任何操作(哪怕是另一个 forEach)都会抛 IllegalStateException。
如果需要多次处理,得重新创建 Stream,比如从原始集合再调一次 list.stream()。
- 错误示例:
Stream s = list.stream().filter(...); s.collect(...); s.count(); // 报错 - 正确做法:每次用新流
list.stream().filter(...).collect(...),或list.stream().filter(...).count()
常见操作分类速查
中间操作(可链式、惰性、返回 Stream): filter、map、flatMap、sorted、distinct、limit、skip、peek
终止操作(触发执行、不可重用、返回结果): collect、forEach、count、findFirst、findAny、anyMatch、allMatch、noneMatch、reduce、toArray、min、max
记住:没有终止操作,Stream 就是纸上谈兵;有了它,整条链才真正动起来。


















