reduce:原文减少,
这里的意思是:根据一定的规则将Stream中的元素进行计算后返回一个唯一的值
举例:
元素求和:
以前我们是这样算的:
Int sum = 0;
for (int x : numbers)
Sum += x;
通过反复使用加法,你把一个数字列表归约成了一个数字;
要是还能把所有的数字相乘,而不必去复制粘贴这段代码,岂不是很好?这正是reduce操作的用武之地,它对这种重复应用的模式做了抽象。你可以像下面这样对流中所有的元素求和:
Int sum = numbers.stream().reduce(0, (a,b) -> a+b);
reduce 接受2个参数:
- 一个初始值,这里是0:
- 一个BinaryOperator<T>来将两个元素结合起来产生一个新值,这里我们用的是lambda(a, b) -> a+b。
也很容易把所有的元素相乘,只需要将另一个Lambda:(a, b) -> a*b 传递给reduce操作就可以了:
int product = numbers.stream().reduce(1, (a,b) -> a*b);
下图展示了reduce操作时如何作用于一个流的:Lambda反复结合每个元素,直到流被归约成一个值。
让我们深入研究一下reduce操作时如何对一个数字流求和的。
首先,0作为Lambda(a)的第一个参数,从流中获取4作为第二个参数(b)。
0+4得到4,它成了新的累积值。
然后再用累积值和流中下一个元素5调用Lambda,产生新的累积值9。
接下来,再用累积值和下一个元素3调用Lambda,得到12。
最后,用12和流中最后一个元素9调用Lambda,得到最终结果21。
你可以使用方法引用让着段代码更简洁。在java8中,Integer类现在有了一个静态的sum方法来对两个数求和,这恰好时我们想要的,用不着反复用Lambda写同一段代码了:
int sum = numbers.stream().reduce(Integer::sum);
无初始值
reduce 还有一个重载的变体,它不接受初始值,但是会返回一个Optional对象:
Optional<Integer> sum = numbers.stream().reduce((a,b) -> a+b);
为什么它返回一个Optional<Integer>呢?考虑流中没有任何元素的情况。
reduce操作无法返回其和,因为它没有初始值。这就是为什么结果被包裹在一个Optional对象里,以表明和可能不存在。现在看看reduce还能做什么。
这里复制了别人的几个例子,非常好用:
数学运算:
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a + b); // 55
int sum2 = Arrays.stream(numbers).reduce(0, Integer::sum); // 55
int sum3 = Arrays.stream(numbers).reduce(0, (a, b) -> a - b); // -55
int sum4 = Arrays.stream(numbers).reduce(0, (a, b) -> a * b); // 0, initial is 0, 0 * whatever = 0
int sum5 = Arrays.stream(numbers).reduce(0, (a, b) -> a / b); // 0
最大和最小:
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int max = Arrays.stream(numbers).reduce(0, (a, b) -> a > b ? a : b); // 10
int max1 = Arrays.stream(numbers).reduce(0, Integer::max); // 10
int min = Arrays.stream(numbers).reduce(0, (a, b) -> a < b ? a : b); // 0
int min1 = Arrays.stream(numbers).reduce(0, Integer::min); // 0
连接字符串:
String[] strings = {"a", "b", "c", "d", "e"};
// |a|b|c|d|e , the initial | join is not what we want
String reduce = Arrays.stream(strings).reduce("", (a, b) -> a + "|" + b);
// a|b|c|d|e, filter the initial "" empty string
String reduce2 = Arrays.stream(strings).reduce("", (a, b) -> {
if (!"".equals(a)) {
return a + "|" + b;
} else {
return b;
}
});
// a|b|c|d|e , better uses the Java 8 String.join :) (最好使用 Java 8 的 String.join)
String join = String.join("|", strings);
map 和 reduce:
一个简单的 map 和 reduce 示例,用于从发票 List 中求 BigDecimal 的和。
package com.mkyong;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
public class JavaReduce {
public static void main(String[] args) {
// 发票集合
List<Invoice> invoices = Arrays.asList(
new Invoice("A01", BigDecimal.valueOf(9.99), BigDecimal.valueOf(1)),
new Invoice("A02", BigDecimal.valueOf(19.99), BigDecimal.valueOf(1.5)),
new Invoice("A03", BigDecimal.valueOf(4.99), BigDecimal.valueOf(2))
);
BigDecimal sum = invoices.stream()
.map(x -> x.getQty().multiply(x.getPrice())) // map,对集合中的元素进行操作
.reduce(BigDecimal.ZERO, BigDecimal::add); // reduce,将上一步得到的结果进行合并得到最终的结果
System.out.println(sum); // 49.955
System.out.println(sum.setScale(2, RoundingMode.HALF_UP)); // 49.96 使用setScale方法进行四舍五入
}
}
class Invoice {
// 发票号码
String invoiceNo;
// 价格
BigDecimal price;
// 数量
BigDecimal qty;
// getters, stters n constructor
}
输出
49.955
49.96
统计坐标点的距离(x,y):
计算某个点到某一批点的最近距离(两点坐标的距离):
public class Position{
private float x;
private float y;
}
private List<Position> batchPosition;
private Position position;
Float distance = batchPosition.stream().map(v -> Math.abs(v.getX() - position.getX()) + Math.abs(v.getY() - position.getY())).reduce(Float::min).orElse(Float.MAX_VALUE);
引用:
https://blog.csdn.net/weixin_44368487/article/details/107658522
https://www.pianshen.com/article/3741873730/