-
CSR
-
Resolution: Approved
-
P4
-
None
-
source
-
minimal
-
-
Java API
-
SE
Summary
Add a new static method teeing
to java.util.stream.Collectors
interface which allows to collect using two independent collectors, then merge their results using the supplied function.
Problem
Sometimes it's desired to collect the stream elements using two collectors. For example, calculate sum and average, or join all elements into string and count them at the same time. Writing the collector which performs these operations from the scratch is non-trivial and error-prone.
Solution
Provide a static method in Collectors
interface (suggested name: teeing
) which accepts two collectors and a BiFunction
to merge their results. The method should return a new Collector
which performs the accumulation using both input collectors, then merges the final results produced by both collectors using the supplied BiFunction
.
An alternative would be to omit a BiFunction
parameter and return instead something like a tuple of both results. However JDK has no suitable tuple class except Map.Entry
which has quite specific semantics. Proposed solution adds more flexibility, as the user might use their own Pair class like teeing(collector1, collector2, Pair::new)
or combine the results in some other way like teeing(summing, counting, (sum, count) -> sum/count)
to get the average value. If Map.Entry
result is desired, teeing(collector1, collector2, Map::entry)
could be used.
Specification
Proposed API method addition (Collectors.java):
/**
* Returns a {@code Collector} that is a composite of two downstream collectors.
* Every element passed to the resulting collector is processed by both downstream
* collectors, then their results are merged using the specified merge function
* into the final result.
*
* <p>The resulting collector functions do the following:
*
* <ul>
* <li>supplier: creates a result container that contains result containers
* obtained by calling each collector's supplier
* <li>accumulator: calls each collector's accumulator with its result container
* and the input element
* <li>combiner: calls each collector's combiner with two result containers
* <li>finisher: calls each collector's finisher with its result container,
* then calls the supplied merger and returns its result.
* </ul>
*
* <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both downstream
* collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both downstream
* collectors are concurrent.
*
* @param <T> the type of the input elements
* @param <R1> the result type of the first collector
* @param <R2> the result type of the second collector
* @param <R> the final result type
* @param downstream1 the first downstream collector
* @param downstream2 the second downstream collector
* @param merger the function which merges two results into the single one
* @return a {@code Collector} which aggregates the results of two supplied collectors.
* @since 12
*/
public static <T, R1, R2, R>
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) { ... }
Full webrev: http://cr.openjdk.java.net/~tvaleev/webrev/8205461/r6/
- csr of
-
JDK-8205461 Create Collector which merges results of two other collectors
- Resolved