约简操作简介
约简操作将汇总操作应用于流的元素以生成一个单独的汇总结果。
流 API 提供了 reduce() 方法来实现约简操作。 该方法有下述三个版本。
-
reduce(accumulator)
:
该版本将 accumulator 函数应用于流的所有元素。在这种情况下没有初始值。
它返回一个含有 accumulator 函数最终结果的 Optional 对象,或者当该流为空时返回一个空的 Optional 对象。
accumulator 函数必须是一个 associative 函数,它实现了 BinaryOperator 接口。
两个参数既可以是流元素,也可以是之前调用 accumulator函数所返回的部分结果。 reduce(identity,accumulator)
:
当最终结果和流的元素类型相同时,必须采用该版本。
标识值必须为 accumulator 函数的标识值。
也就是说,如果将 accumulator 函数应用于标识值和任意值 V ,必须返回同样的值 V : accumulator(identity,V)=V 。
该标识值用作 accumulator 函数的第一个结果,如果流没有元素,则该值作为返回值。
正如在另一版本中一样, accumulator 必须是一个实现 BinaryOperator 接口的 associative 函数。reduce(identity, accumulator, combiner)
:
当最终结果与流的元素为不同类型时,必须使用该版本。
标识值必须是 combiner 函数的标识。也就是说, combiner(identity,v)=v 。
这里的 combiner 函数必须与 accumulator 函数兼容,即 combiner(u,accumulator(identity,v))=accumulator(u,v) 。
accumulator 函数采用局部结果和流的下一个元素生成另一个局部结果。
combiner 函数采用两个局部结果来生成另一个局部结果。
这两个函数必须均是 associative 函数,但是在这种情况下, accumulator 函数是 BiFunction 接口的实现,而 combiner 函数是 BinaryOperator 接口的实现。
reduce() 方法有一个局限。如前所述,该函数必须返回单个值。
你不应该使用 reduce() 方法来生成一个 Collection 对象或者一个复杂对象。
-
首要问题在于性能。正如流 API 的文档中所说明的,accumulator 函数每处理一个元素都会返回一个新值。
如果你的 accumulator 函数处理的是集合,那么每当它处理一个元素时都会创建一个新的集合,这样效率就很低。 -
另一个问题是,如果采用并行流,那么所有的线程都要共享标识值。
如果要实现一个可生成 Collection 或复杂对象的约简操作,有如下两个供选方案。
-
使用 collect() 方法应用可变约简操作。
-
创建集合并且使用 forEach() 方法,以便使用所需值填充 Collection 。