Java Stream 是 Java 8 引入的函数式编程核心工具,以惰性管道方式处理数据:从集合、数组等源创建,经 filter/map/flatMap 等中间操作链式转换,最终由 forEach/collect/reduce 等终止操作触发执行,需注意并行流的适用场景与线程安全陷阱。

Java Stream 是 Java 8 引入的函数式编程核心工具,它不改变原集合,而是以“管道”方式对数据进行声明式处理——写得少、读得清、改得快。
Stream 创建:从哪来?
Stream 本身不存储数据,必须基于已有数据源创建:
- 集合转 Stream:用 collection.stream()(串行)或 collection.parallelStream()(并行)
- 数组转 Stream:用 Arrays.stream(arr) 或 Stream.of(arr)(后者支持可变参数)
- 生成无限流:用 Stream.iterate(0, n -> n + 1)(按规则迭代)或 Stream.generate(Math::random)(按 Supplier 生成)
- 静态工厂方法:如 Stream.empty()、Stream.of("a", "b")、Files.lines(path)(文件行流)
中间操作:链式处理,惰性执行
中间操作返回新 Stream,不触发计算,只“记下要做什么”。常见操作有:
-
filter(Predicate):筛选,比如
stream.filter(x -> x > 10) -
map(Function):转换,比如
stream.map(String::toUpperCase) - flatMap(Function<T, Stream<R>>):扁平化,适合处理嵌套结构(如 List<List<String>> → Stream<String>)
- distinct():去重(依赖元素 equals/hashCode)
- sorted():排序(无参按自然序;传 Comparator 自定义)
- limit(n) / skip(n):截取或跳过前 n 个元素
注意:多个中间操作会合并优化(如连续 filter 可能合并),但不会立即执行。
立即学习“Java免费学习笔记(深入)”;
终止操作:一锤定音,触发执行
终止操作消耗 Stream,产生非 Stream 结果(值、集合、副作用等),执行后 Stream 就失效了:
- forEach(Consumer):遍历(不保证顺序,多线程下慎用)
-
collect(Collector):最常用,转成 List/Map/Set 或自定义聚合,如
collect(Collectors.toList()) -
reduce(BinaryOperator):归约,如求和
reduce(0, Integer::sum),支持带 identity 和 accumulator 的三参数重载 - anyMatch / allMatch / noneMatch(Predicate):短路匹配,效率高
- findFirst() / findAny():获取 Optional 结果(前者保证顺序,后者并行时更高效)
- count():返回 long 类型元素总数
并行与陷阱:别盲目用 parallelStream()
parallelStream() 背后是 ForkJoinPool,默认使用 CPU 核心数线程。但它不是银弹:
- 适用场景:数据量大、操作耗时、无强顺序依赖(如 map/filter/reduce)、线程安全(避免共享可变状态)
- 慎用情况:小数据集(开销反超收益)、IO 操作(阻塞线程拖慢整体)、需要保持插入顺序(如 forEach 不保证顺序)
- 常见坑:在 parallelStream 中修改外部变量(如 ++i)、使用非线程安全集合(如 ArrayList.add)、错误假设执行顺序
不确定时,优先用 stream();确认瓶颈后再测 parallelStream(),并用 JMH 做基准测试。
Stream 写法简洁,但关键在理解“数据源 → 中间操作(惰性)→ 终止操作(执行)”这条链。写之前想清楚:是否真需要函数式风格?是否比传统 for 更清晰?是否考虑了并发安全和性能边界?搞懂这三点,Stream 就不难用好。


















