在java
中,分为Collectors.reducing
和Stream#reduce
reduce
是减少的意思,此处意为聚合
聚合是聚拢、合并的意思
我们来看看这俩函数的区别吧,下方我用了静态导入:
代码语言:javascript复制import java.math.BigDecimal;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.stream.Collector;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
首先是写法差异,对于只有一个参数的,这个参数指定了我们聚合的操作,此处我做一个累加,返回值为Optional
证明有可能不存在值,就没有累加
Optional<Integer> sumOpt = Stream.iterate(0, i -> i).limit(10).collect(reducing(Integer::sum));
System.out.println(sumOpt); // Optional[45]
sumOpt = Stream.iterate(0, i -> i).limit(10).reduce(Integer::sum);
System.out.println(sumOpt); // Optional[45]
两个参数的,这里第一个参数为默认值,这里返回的是默认值 累加后的结果,此处默认值只能指定为相同类型
代码语言:javascript复制Integer sum = Stream.iterate(0, i -> i).limit(10).collect(reducing(10, Integer::sum));
System.out.println(sum); // 55
sum = Stream.iterate(0, i -> i).limit(10).reduce(10, Integer::sum);
System.out.println(sum); // 55
到此为止,其实都差不多,下面是三个参数的,这个三参用于聚合为其他类型的默认值,第一个参数还是默认值,第二个参数和第三个参数就有区别了
代码语言:javascript复制BigDecimal sumDecimal = Stream.iterate(0, i -> i).limit(10).collect(
reducing(BigDecimal.ZERO, BigDecimal::new, BigDecimal::add));
System.out.println(sumDecimal); // 45
sumDecimal = Stream.iterate(0, i -> i).limit(10)
.reduce(BigDecimal.ZERO, (d, i) -> d.add(new BigDecimal(i)), BigDecimal::add);
System.out.println(sumDecimal); // 45
可以看出我们的Collectors.reducing
第二个参数是一个Function<Integer,BigDecimal>
,入参为Integer
返回值为BigDecimal
,并没有进行聚合运算,而是进行了一个转换,此处是由Integer
去生成一个BigDecimal
,调用的java.math.BigDecimal#BigDecimal(int)
这个构造,而第三个参数才是我们的累加操作
但Stream#reduce
中,第二个参数是一个BiFunction<BigDecimal, Integer, BigDecimal>
,入参变为两个参数BigDecimal
(已经累加的结果,并行流下值不可控)和Integer
(本次参与运算的值),返回值为BigDecimal
(运算结果),第三个参数是个BinaryOperator<BigDecimal>
只在并行流场景下会用到,之前讲过,这里就不再表了,贴上链接:
reduce补充二
第三个参数区别:
也就是说,我们在串行流中哪怕将Stream#reduce
的第三个参数,改为任意操作,他都是不影响结果执行的,例如我们这里取最大值
BigDecimal sumDecimal = Stream.iterate(0, i -> i).limit(10).collect(
reducing(BigDecimal.ZERO, BigDecimal::new, BinaryOperator.maxBy(BigDecimal::compareTo)));
System.out.println(sumDecimal); // 9
sumDecimal = Stream.iterate(0, i -> i).limit(10)
.reduce(BigDecimal.ZERO, (d, i) -> d.add(new BigDecimal(i)), BinaryOperator.maxBy(BigDecimal::compareTo));
System.out.println(sumDecimal); // 45
可以看出,哪怕我们改为BinaryOperator.maxBy(BigDecimal::compareTo)
,是不影响Stream#reduce
的,哪怕我们改为null
BigDecimal sumDecimal = Stream.iterate(0, i -> i).limit(10).collect(
reducing(BigDecimal.ZERO, BigDecimal::new, (l, r) -> null));
System.out.println(sumDecimal); // null
sumDecimal = Stream.iterate(0, i -> i).limit(10)
.reduce(BigDecimal.ZERO, (d, i) -> d.add(new BigDecimal(i)), (l, r) -> null);
System.out.println(sumDecimal); // 45
除非并行流场景下:
代码语言:javascript复制Optional<Integer> sumOpt = Stream.iterate(0, i -> i).parallel().limit(10).collect(reducing(Integer::sum));
System.out.println(sumOpt); // Optional[45]
sumOpt = Stream.iterate(0, i -> i).parallel().limit(10).reduce(Integer::sum);
System.out.println(sumOpt); // Optional[45]
Integer sum = Stream.iterate(0, i -> i).parallel().limit(10).collect(reducing(10, Integer::sum));
System.out.println(sum); // 145
sum = Stream.iterate(0, i -> i).parallel().limit(10).reduce(10, Integer::sum);
System.out.println(sum); // 145
BigDecimal sumDecimal = Stream.iterate(0, i -> i).parallel().limit(10).collect(
reducing(BigDecimal.ZERO, BigDecimal::new, (l, r) -> null));
System.out.println(sumDecimal); // null
sumDecimal = Stream.iterate(0, i -> i).parallel().limit(10)
.reduce(BigDecimal.ZERO, (d, i) -> d.add(new BigDecimal(i)), (l, r) -> null);
System.out.println(sumDecimal); // null
我们再次改为求最大值
代码语言:javascript复制BigDecimal sumDecimal = Stream.iterate(0, i -> i).parallel().limit(10).collect(
reducing(BigDecimal.ZERO, BigDecimal::new, BinaryOperator.maxBy(BigDecimal::compareTo)));
System.out.println(sumDecimal); // 9
sumDecimal = Stream.iterate(0, i -> i).parallel().limit(10)
.reduce(BigDecimal.ZERO, (d, i) -> d.add(new BigDecimal(i)), BinaryOperator.maxBy(BigDecimal::compareTo));
System.out.println(sumDecimal); // 9
可以看到并行流场景下均生效