前言:
JDK 12中添加了一个新的流API收集器:Teeing()。
简单地说,它允许使用两个独立的收集器收集流,然后使用提供的双功能合并结果。
例如,通过使用它可以计算所有流值的预期值:
// import static java.util.stream.Collectors.*;
Double ev = Stream.of(1, 2, 3, 4, 5, 6) // dice roll
.collect(teeing(
summingDouble(i -> i),
counting(),
(sum, n) -> sum / n));
System.out.println(ev); // 3.5
或者可以派生一个新的收集器,它也可以这样做:
private static Collector derivingExpectedValue() {
return teeing(
summingDouble(i -> i),
counting(),
(sum, n) -> sum / n);
}
Double ev = Stream.of(1, 2, 3, 4, 5, 6)
.collect(derivingExpectedValue());
Teeing()
同 Collectors#groupingBy. 的使用: https://4comprehension.com/the-ultimate-guide-to-the-java-stream-api-groupingby-collector/
Integer[] stream = Stream.of(1, 2, 3, 4, 5, 6).toArray(Integer[]::new);
Double ev = IntStream.range(0, stream.length).boxed()
.reduce(0d, (acc, i) -> acc + (((double) stream[i]) / stream.length), (acc1, acc2) -> cc1 + acc2);
或者
Integer[] stream = Stream.of(1, 2, 3, 4, 5, 6).toArray(Integer[]::new);
double ev = 0d;
for (Integer integer : stream) {
ev = ev + (((double) integer) / stream.length);
}
实现机制:
public static Collector 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 Collector 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 c1Supplier = Objects.requireNonNull(
downstream1.supplier(), "downstream1 supplier");
Supplier c2Supplier = Objects.requireNonNull(
downstream2.supplier(), "downstream2 supplier");
BiConsumer c1Accumulator = Objects.requireNonNull(
downstream1.accumulator(), "downstream1 accumulator");
BiConsumer c2Accumulator = Objects.requireNonNull(
downstream2.accumulator(), "downstream2 accumulator");
BinaryOperator c1Combiner = Objects.requireNonNull(
downstream1.combiner(), "downstream1 combiner");
BinaryOperator c2Combiner = Objects.requireNonNull(
downstream2.combiner(), "downstream2 combiner");
Function c1Finisher = Objects.requireNonNull(
downstream1.finisher(), "downstream1 finisher");
Function c2Finisher = Objects.requireNonNull(
downstream2.finisher(), "downstream2 finisher");
Set characteristics;
Set c1Characteristics = downstream1
.characteristics();
Set c2Characteristics = downstream2
.characteristics();
if (CH_ID.containsAll(c1Characteristics)
|| CH_ID.containsAll(c2Characteristics)) {
characteristics = CH_NOID;
} else {
EnumSet 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);
}
详情参考: https://bugs.openjdk.java.net/browse/JDK-8209685