I think Reduction operations paragraph from java.util.stream
package summary can answer the question. Let me cite the most important part here:
In its more general form, a reduce operation on elements of type <T>
yielding a result of type <U>
requires three parameters:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
Here, the identity element is both an initial seed value for the reduction and a default result if there are no input elements. The accumulator function takes a partial result and the next element, and produces a new partial result. The combiner function combines two partial results to produce a new partial result. (The combiner is necessary in parallel reductions, where the input is partitioned, a partial accumulation computed for each partition, and then the partial results are combined to produce a final result.)
More formally, the identity value must be an identity for the combiner function. This means that for all u
, combiner.apply(identity, u)
is equal to u
. Additionally, the combiner function must be associative and must be compatible with the accumulator function: for all u
and t
, combiner.apply(u, accumulator.apply(identity, t))
must be equals()
to accumulator.apply(u, t)
.
The three-argument form is a generalization of the two-argument form, incorporating a mapping step into the accumulation step. We could re-cast the simple sum-of-weights example using the more general form as follows:
int sumOfWeights = widgets.stream()
.reduce(0,
(sum, b) -> sum + b.getWeight())
Integer::sum);
though the explicit map-reduce form is more readable and therefore should usually be preferred. The generalized form is provided for cases where significant work can be optimized away by combining mapping and reducing into a single function.
In other words, as far as I understand, the three-argument form is useful in two cases:
- When parallel execution matters.
- When significant performance optimization can be achieved by combining mapping and accumulation steps. Otherwise more simple and readable explicit map-reduce form can be used.
Explicit form is mentioned previously in the same doc:
int sumOfWeights = widgets.parallelStream()
.filter(b -> b.getColor() == RED)
.mapToInt(b -> b.getWeight())
.sum();