文章目录
- 294. Java Stream API - 对流进行归约
- 🎯 什么是归约(Reduction)?
- ✅ 什么是终端操作?
- 🔔 注意事项:
- 🧠 使用 `BinaryOperator` 对流进行归约
- 🧪 示例一:经典求和
- 🔁 示例二:使用 BinaryOperator 改写
- 🧪 示例三:计算最大值(MAX)
- ☕ Stream API 中的 reduce() 方法
- 🧪 示例四:带初始值的 reduce(避免 Optional)
- 📌 小结
- 🧠 延伸思考
294. Java Stream API - 对流进行归约
🎯 什么是归约(Reduction)?
在Java Stream API中,所谓的归约操作,其实就像 SQL 中的聚合操作 —— 比如SUM(),MAX()等。我们通过一个终端操作(Terminal Operation)来将流中的多个元素聚合成一个结果。
✅ 什么是终端操作?
终端操作会触发整个流的执行,常见的包括:
collect()(如:collect(Collectors.toList()))reduce()(本节主角)forEach()count()anyMatch(),allMatch(), 等
🔔 注意事项:
- 没有终端操作的流不会执行任何处理!
- 如果你看到一个只调用了
map()或filter()但没有终端操作的流,那就是个 bug。
- 如果你看到一个只调用了
- 每个 Stream 实例只能执行一次终端操作!
- 流一旦执行终端操作,就会“关闭”,不能再使用,否则会抛出
IllegalStateException。
- 流一旦执行终端操作,就会“关闭”,不能再使用,否则会抛出
🧠 使用BinaryOperator对流进行归约
Java中reduce()方法的核心,就是使用一个二元操作符(BinaryOperator)将两个元素合并成一个,不断迭代直到只剩一个值。
🧪 示例一:经典求和
我们先用传统 for 循环来实现整数列表求和:
List<Integer>ints=List.of(3,6,2,1);intsum=ints.get(0);for(inti=1;i<ints.size();i++){sum+=ints.get(i);}System.out.println("sum = "+sum);🟢 输出:
sum=12🔍 这个过程就是不断把前面计算的“部分和”与下一个元素相加。
🔁 示例二:使用 BinaryOperator 改写
我们可以将“加法”逻辑抽象成一个BinaryOperator:
List<Integer>ints=List.of(3,6,2,1);BinaryOperator<Integer>sum=(a,b)->a+b;intresult=ints.get(0);for(inti=1;i<ints.size();i++){result=sum.apply(result,ints.get(i));}System.out.println("sum = "+result);🟢 输出:
sum=12🎯 好处:只需要更换BinaryOperator,就能实现其他聚合操作!
🧪 示例三:计算最大值(MAX)
只需将 BinaryOperator 换成一个“取较大值”的函数:
List<Integer>ints=List.of(3,6,2,1);BinaryOperator<Integer>max=(a,b)->a>b?a:b;intresult=ints.get(0);for(inti=1;i<ints.size();i++){result=max.apply(result,ints.get(i));}System.out.println("max = "+result);🟢 输出:
max=6☕ Stream API 中的 reduce() 方法
现在让我们用Stream 的 reduce() 方法来实现相同逻辑。reduce()有多个重载版本,这里我们使用最基础的一种:
List<Integer>ints=List.of(3,6,2,1);Optional<Integer>sum=ints.stream().reduce((a,b)->a+b);sum.ifPresent(s->System.out.println("sum = "+s));🟢 输出:
sum=12🔎
reduce()返回的是Optional<T>,因为当流为空时,没有结果。
🧪 示例四:带初始值的 reduce(避免 Optional)
List<Integer>ints=List.of(3,6,2,1);intsum=ints.stream().reduce(0,(a,b)->a+b);System.out.println("sum = "+sum);🟢 输出:
sum=12🎯 传入初始值后,reduce()会从这个值开始进行归约,并返回确定的类型(非 Optional)。
📌 小结
| 特性 | 说明 |
|---|---|
| ✅ 终端操作 | reduce()是一种终端操作,用于聚合流元素 |
| 🔄 可变操作 | 只需变换BinaryOperator即可进行加总、取最大、最小等操作 |
| 💡 Optional 处理 | 不传初始值时返回Optional,可避免空流 NPE |
| ♻️ 不可复用 | Stream 使用一次后即失效,请勿复用 |
🧠 延伸思考
reduce()可以用于更多复杂的聚合计算,例如拼接字符串、合并集合等。- 在并行流中(
parallelStream()),reduce()的初始值需要满足结合律,以确保并发结果一致。