java8新特性-reduce
reduce是用来执行聚合操作的
reduce方法有三个override的方法:
Optional<T> reduce(BinaryOperator<T> accumulator); T reduce(T identity, BinaryOperator<T> accumulator); <U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> 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("--------"); return acc; }); System.out.println("accResult: " + accResult.get()); System.out.println("--------"); // 结果打印 -------- acc : 1 item: 2 acc+ : 3 -------- acc : 3 item: 3 acc+ : 6 -------- acc : 6 item: 4 acc+ : 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("--------"); return acc; }); System.out.println("accResult: " + accResult); System.out.println("--------"); // 结果打印 acc : 0 item: 1 acc+ : 1 -------- acc : 1 item: 2 acc+ : 3 -------- acc : 3 item: 3 acc+ : 6 -------- acc : 6 item: 4 acc+ : 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<Integer> accResult_ = Stream.of(1, 2, 3, 4) .reduce(new ArrayList<Integer>(), new BiFunction<ArrayList<Integer>, Integer, ArrayList<Integer>>() { @Override public ArrayList<Integer> apply(ArrayList<Integer> acc, Integer item) { acc.add(item); System.out.println("item: " + item); System.out.println("acc+ : " + acc); System.out.println("BiFunction"); return acc; } }, new BinaryOperator<ArrayList<Integer>>() { @Override public ArrayList<Integer> apply(ArrayList<Integer> acc, ArrayList<Integer> item) { System.out.println("BinaryOperator"); acc.addAll(item); System.out.println("item: " + item); System.out.println("acc+ : " + acc); System.out.println("--------"); return acc; } }); System.out.println("accResult_: " + accResult_); // 结果打印 item: 1 acc+ : [1] BiFunction item: 2 acc+ : [1, 2] BiFunction item: 3 acc+ : [1, 2, 3] BiFunction item: 4 acc+ : [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<HisLinksIndicesRanking> hisLinksIndicesRankingList) -> { HisLinksIndicesRankingCalcBo hisLinksIndicesRankingCalcBo = new HisLinksIndicesRankingCalcBo(new HisLinksIndicesRanking()); 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 { return b; } }); // 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