< prev index next >
src/java.base/share/classes/java/util/stream/Collectors.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 1883,1892 ****
--- 1883,1988 ----
(r, t) -> r.accept(mapper.applyAsDouble(t)),
(l, r) -> { l.combine(r); return l; }, CH_ID);
}
/**
+ * 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) {
+ return teeing0(downstream1, downstream2, merger);
+ }
+
+ private static <T, A1, A2, R1, R2, R>
+ Collector<T, ?, R> teeing0(Collector<? super T, A1, R1> downstream1,
+ Collector<? super T, A2, R2> downstream2,
+ BiFunction<? super R1, ? super R2, R> merger) {
+ Objects.requireNonNull(downstream1, "downstream1");
+ Objects.requireNonNull(downstream2, "downstream2");
+ Objects.requireNonNull(merger, "merger");
+
+ Supplier<A1> c1Supplier = Objects.requireNonNull(downstream1.supplier(), "downstream1 supplier");
+ Supplier<A2> c2Supplier = Objects.requireNonNull(downstream2.supplier(), "downstream2 supplier");
+ BiConsumer<A1, ? super T> c1Accumulator =
+ Objects.requireNonNull(downstream1.accumulator(), "downstream1 accumulator");
+ BiConsumer<A2, ? super T> c2Accumulator =
+ Objects.requireNonNull(downstream2.accumulator(), "downstream2 accumulator");
+ BinaryOperator<A1> c1Combiner = Objects.requireNonNull(downstream1.combiner(), "downstream1 combiner");
+ BinaryOperator<A2> c2Combiner = Objects.requireNonNull(downstream2.combiner(), "downstream2 combiner");
+ Function<A1, R1> c1Finisher = Objects.requireNonNull(downstream1.finisher(), "downstream1 finisher");
+ Function<A2, R2> c2Finisher = Objects.requireNonNull(downstream2.finisher(), "downstream2 finisher");
+
+ Set<Collector.Characteristics> characteristics;
+ Set<Collector.Characteristics> c1Characteristics = downstream1.characteristics();
+ Set<Collector.Characteristics> c2Characteristics = downstream2.characteristics();
+ if (CH_ID.containsAll(c1Characteristics) || CH_ID.containsAll(c2Characteristics)) {
+ characteristics = CH_NOID;
+ } else {
+ EnumSet<Collector.Characteristics> c = EnumSet.noneOf(Collector.Characteristics.class);
+ c.addAll(c1Characteristics);
+ c.retainAll(c2Characteristics);
+ c.remove(Collector.Characteristics.IDENTITY_FINISH);
+ characteristics = Collections.unmodifiableSet(c);
+ }
+
+ 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 merger.apply(r1, r2);
+ }
+ }
+
+ return new CollectorImpl<>(PairBox::new, PairBox::add, PairBox::combine, PairBox::get, characteristics);
+ }
+
+ /**
* Implementation class used by partitioningBy.
*/
private static final class Partition<T>
extends AbstractMap<Boolean, T>
implements Map<Boolean, T> {
< prev index next >