< prev index next >

src/java.base/share/classes/java/util/stream/Collectors.java

Print this page

        

@@ -1883,10 +1883,82 @@
                 (r, t) -> r.accept(mapper.applyAsDouble(t)),
                 (l, r) -> { l.combine(r); return l; }, CH_ID);
     }
 
     /**
+     * Returns a {@code Collector} that passes the input elements to two specified collectors
+     * and merges their results with the specified merge function.
+     *
+     * <p>The resulting collector is {@link Collector.Characteristics#UNORDERED} if both supplied
+     * collectors are unordered and {@link Collector.Characteristics#CONCURRENT} if both supplied
+     * 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 c1       the first collector
+     * @param c2       the second collector
+     * @param finisher 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> pairing(Collector<? super T, ?, R1> c1,
+                               Collector<? super T, ?, R2> c2,
+                               BiFunction<? super R1, ? super R2, ? extends R> finisher) {
+        return pairing0(c1, c2, finisher);
+    }
+
+    private static <T, A1, A2, R1, R2, R>
+    Collector<T, ?, R> pairing0(Collector<? super T, A1, R1> c1,
+                                Collector<? super T, A2, R2> c2,
+                                BiFunction<? super R1, ? super R2, ? extends R> finisher) {
+        Objects.requireNonNull(c1, "c1");
+        Objects.requireNonNull(c2, "c2");
+        Objects.requireNonNull(finisher, "finisher");
+        EnumSet<Collector.Characteristics> c = EnumSet.noneOf(Collector.Characteristics.class);
+        c.addAll(c1.characteristics());
+        c.retainAll(c2.characteristics());
+        c.remove(Collector.Characteristics.IDENTITY_FINISH);
+
+        Supplier<A1> c1Supplier = Objects.requireNonNull(c1.supplier(), "c1 supplier");
+        Supplier<A2> c2Supplier = Objects.requireNonNull(c2.supplier(), "c2 supplier");
+        BiConsumer<A1, ? super T> c1Accumulator = Objects.requireNonNull(c1.accumulator(), "c1 accumulator");
+        BiConsumer<A2, ? super T> c2Accumulator = Objects.requireNonNull(c2.accumulator(), "c2 accumulator");
+        BinaryOperator<A1> c1Combiner = Objects.requireNonNull(c1.combiner(), "c1 combiner");
+        BinaryOperator<A2> c2Combiner = Objects.requireNonNull(c2.combiner(), "c2 combiner");
+        Function<A1, R1> c1Finisher = Objects.requireNonNull(c1.finisher(), "c1 finisher");
+        Function<A2, R2> c2Finisher = Objects.requireNonNull(c2.finisher(), "c2 finisher");
+
+        class PairBox {
+            A1 left = c1Supplier.get();
+            A2 right = c2Supplier.get();
+
+            void add(T t) {
+                c1Accumulator.accept(left, t);
+                c2Accumulator.accept(right, t);
+            }
+
+            PairBox combine(PairBox other) {
+                left = c1Combiner.apply(left, other.left);
+                right = c2Combiner.apply(right, other.right);
+                return this;
+            }
+
+            R get() {
+                R1 r1 = c1Finisher.apply(left);
+                R2 r2 = c2Finisher.apply(right);
+                return finisher.apply(r1, r2);
+            }
+        }
+
+        return new CollectorImpl<>(PairBox::new, PairBox::add, PairBox::combine, PairBox::get,
+                Collections.unmodifiableSet(c));
+    }
+
+    /**
      * Implementation class used by partitioningBy.
      */
     private static final class Partition<T>
             extends AbstractMap<Boolean, T>
             implements Map<Boolean, T> {
< prev index next >