reduce是用来执行聚合操作的
reduce方法有三个override的方法:
Optional reduce(BinaryOperator accumulator);
T reduce(T identity, BinaryOperator accumulator);
U reduce(U identity,BiFunction accumulator,BinaryOperator combiner);
1. 第一种方法
BinaryOperator接口,可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。这个方法返回值类型是Optional。
Optional accResult = Stream.of(1, 2, 3, 4)
.reduce((acc, item)->{
System.out.println("acc :" +acc);
acc+=item;
System.out.println("item:" +item);
System.out.println("acc+ :" +acc);
System.out.println("--------");returnacc;
});
System.out.println("accResult:" + accResult.get());
System.out.println("--------");//结果打印
--------acc :1item:2acc+ : 3
--------acc :3item:3acc+ : 6
--------acc :6item:4acc+ : 10
--------accResult:10
--------
2. 第二种方法
第二个变形,与第一种变形相同的是都会接受一个BinaryOperator函数接口,不同的是其会接受一个identity参数,用来指定Stream循环的初始值。如果Stream为空,就直接返回该值。另一方面,该方法不会返回Optional,因为该方法不会出现null。
int accResult = Stream.of(1, 2, 3, 4)
.reduce(0, (acc, item) ->{
System.out.println("acc :" +acc);
acc+=item;
System.out.println("item:" +item);
System.out.println("acc+ :" +acc);
System.out.println("--------");returnacc;
});
System.out.println("accResult:" +accResult);
System.out.println("--------");//结果打印
acc : 0item:1acc+ : 1
--------acc :1item:2acc+ : 3
--------acc :3item:3acc+ : 6
--------acc :6item:4acc+ : 10
--------accResult:10
--------
从打印结果可以看出,reduce前两种变形,因为接受参数不同,其执行的操作也有相应变化:
变形1,未定义初始值,从而第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素
变形2,定义了初始值,从而第一次执行的时候第一个参数的值是初始值,第二个参数是Stream的第一个元素
第三种方法
第一个参数返回实例u,传递你要返回的U类型对象的初始化实例u,第二个参数累加器accumulator,可以使用二元?表达式(即二元lambda表达式),声明你在u上累加你的数据来源t的逻辑,例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t,第三个参数组合器combiner,同样是二元?表达式,(u,t)->u。
因为reduce的变形的第一个参数类型是实际返回实例的数据类型,同时其为一个泛型也就是意味着该变形的可以返回任意类型的数据。从上面文档介绍的字面意思解读是第三个参数函数用来组合两个值,而这两个值必须与第二个函数参数相兼容,也就是说它们所得的结果是一样的。看到这里肯定有迷惑的地方,第三个参数到底是用来干嘛的?我们先看一段代码,为了便于了解其中的缘由,并没有使用Lambda表达式。
ArrayList accResult_ = Stream.of(1, 2, 3, 4)
.reduce(new ArrayList(),new BiFunction, Integer, ArrayList>() {
@Overridepublic ArrayList apply(ArrayListacc, Integer item) {
acc.add(item);
System.out.println("item:" +item);
System.out.println("acc+ :" +acc);
System.out.println("BiFunction");returnacc;
}
},new BinaryOperator>() {
@Overridepublic ArrayList apply(ArrayList acc, ArrayListitem) {
System.out.println("BinaryOperator");
acc.addAll(item);
System.out.println("item:" +item);
System.out.println("acc+ :" +acc);
System.out.println("--------");returnacc;
}
});
System.out.println("accResult_:" +accResult_);//结果打印
item: 1acc+ : [1]
BiFunction
item:2acc+ : [1, 2]
BiFunction
item:3acc+ : [1, 2, 3]
BiFunction
item:4acc+ : [1, 2, 3, 4]
BiFunction
accResult_: [1, 2, 3, 4]
accResult_:10
首先示例代码中,传递给第一个参数是ArrayList,在第二个函数参数中打印了“BiFunction”,而在第三个参数接口中打印了函数接口中打印了”BinaryOperator“.可是,看打印结果,只是打印了“BiFunction”,而没有打印”BinaryOperator“,说明第三个函数参数并没有执行。这里我们知道了该变形可以返回任意类型的数据。对于第三个函数参数,为什么没有执行,刚开始的时候也是没有看懂到底是啥意思呢,而且其参数必须为返回的数据类型?看了好几遍文档也是一头雾水。在 java8 reduce方法中的第三个参数combiner有什么作用?这里找到了答案,Stream是支持并发操作的,为了避免竞争,对于reduce线程都会有独立的result,combiner的作用在于合并每个线程的result得到最终结果。这也说明了了第三个函数参数的数据类型必须为返回数据类型了。
参考:https://blog.csdn.net/zhang89xiao/article/details/77164866?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-2.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-2.nonecase
使用reduce实现分组统计
filterHistoryRankingList.stream().collect(Collectors.groupingBy(p -> p.getAdcode() + "_" + p.getLinksType() + "_" +p.getId()))
.forEach((String mapKey, List hisLinksIndicesRankingList) ->{
HisLinksIndicesRankingCalcBo hisLinksIndicesRankingCalcBo= new HisLinksIndicesRankingCalcBo(newHisLinksIndicesRanking());
hisLinksIndicesRankingList.stream().reduce(hisLinksIndicesRankingCalcBo, (u, t)-> u.calcRoad(t), (u, t) ->u);
resList.add(hisLinksIndicesRankingCalcBo.getHisLinksIndicesRanking());
});
数字累加
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//1st argument, init value = 0
int sum = Arrays.stream(numbers).reduce(0, (a, b) -> a +b);
System.out.println("sum :" + sum); //55
最大最小
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{returnb;
}
});//a|b|c|d|e , better uses the Java 8 String.join :) (最好使用 Java 8 的 String.join)
String join = String.join("|", strings);
参考:https://www.cnblogs.com/gaohanghang/p/12390233.html