Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8209685

Create Collector which merges results of two other collectors

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P4
    • 12
    • core-libs
    • None
    • source
    • minimal
    • Hide
      It's possible, though highly unlikely that "import static java.util.Collectors.*;" is used in existing code and "teeing" method with compatible signature is imported from somewhere else and used. In this case wrong method could be linked.
      Show
      It's possible, though highly unlikely that "import static java.util.Collectors.*;" is used in existing code and "teeing" method with compatible signature is imported from somewhere else and used. In this case wrong method could be linked.
    • Java API
    • SE

    Description

      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/

      Attachments

        Issue Links

          Activity

            People

              tvaleev Tagir Valeev
              tvaleev Tagir Valeev
              Stuart Marks
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: