后端开发
Java Stream Transform:流式数据处理的艺术
{}
Stream 是什么?
Java 8 引入的 Stream API 是对集合操作的声明式抽象。它不是数据结构,而是一套描述数据 Transform 管道 的接口。核心思想是:数据经过一系列中间操作(map/filter/sorted)的变换,最终由终止操作(collect/reduce/forEach)触发执行。
三种核心 Transform 操作
1. map -- 元素映射
map 是最纯粹的 Transform:对每个元素应用函数,产生新元素。
List<String> names = List.of("alice", "bob", "charlie");
List<String> upper = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
2. flatMap -- 扁平化映射
当映射结果本身是流时,flatMap 将多个流合并为一个:
List<List<Integer>> nested = List.of(
List.of(1, 2), List.of(3, 4), List.of(5));
List<Integer> flat = nested.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
3. reduce -- 归约聚合
reduce 将流中的元素反复结合,最终归约为一个值:
int sum = IntStream.range(1, 101)
.reduce(0, Integer::sum);
懒求值机制
Stream 的中间操作是 惰性 的 -- 它们不会立即执行,直到遇到终止操作。这使得无限流成为可能:
// 生成前 10 个偶数的平方
List<Integer> squares = IntStream.iterate(1, n -> n + 1)
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.limit(10)
.boxed()
.collect(Collectors.toList());
如果没有 limit,collect 会永远等待。正是因为懒求值,filter 和 map 不会提前处理所有元素。
并行流 Parallel Stream
只需将 stream() 改为 parallelStream(),框架自动利用 ForkJoinPool 进行并行处理:
long count = list.parallelStream()
.filter(x -> x > 100)
.count();
但要注意:并行不总是更快。对于小数据集或 IO 密集操作,线程切换的开销可能超过收益。
Collector 的组合艺术
Collectors.groupingBy 结合 mapping 和 reducing 可以构建强大的分组聚合:
// 按部门分组,求每个部门的平均薪资
Map<String, Double> avgSalary = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDept,
Collectors.averagingDouble(Employee::getSalary)));
Map<String, Optional<Employee>> topEarner = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDept,
Collectors.maxBy(Comparator.comparing(Employee::getSalary))));
Stream 的本质是函数式编程中的 Transform 组合 -- 你描述"做什么",而不是"怎么做",让框架去优化"怎么做"。