JDK 12 and above has Collectors.teeing
(webrev and CSR), which collects to two different collectors and then merges both partial results into a final result.
You could use it here to collect to two IntSummaryStatistics
for both the x
coordinate and the y
coordinate:
List<IntSummaryStatistics> stats = points.stream()
.collect(Collectors.teeing(
Collectors.mapping(p -> p.x, Collectors.summarizingInt()),
Collectors.mapping(p -> p.y, Collectors.summarizingInt()),
List::of));
int minX = stats.get(0).getMin();
int maxX = stats.get(0).getMax();
int minY = stats.get(1).getMin();
int maxY = stats.get(1).getMax();
Here the first collector gathers statistics for x
and the second one for y
. Then, statistics for both x
and y
are merged into a List
by means of the JDK 9 List.of
factory method that accepts two elements.
An aternative to List::of
for the merger would be:
(xStats, yStats) -> Arrays.asList(xStats, yStats)
If you happen to not have JDK 12 installed on your machine, here’s a simplified, generic version of the teeing
method that you can safely use as a utility method:
public static <T, A1, A2, R1, R2, R> Collector<T, ?, R> teeing(
Collector<? super T, A1, R1> downstream1,
Collector<? super T, A2, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) {
class Acc {
A1 acc1 = downstream1.supplier().get();
A2 acc2 = downstream2.supplier().get();
void accumulate(T t) {
downstream1.accumulator().accept(acc1, t);
downstream2.accumulator().accept(acc2, t);
}
Acc combine(Acc other) {
acc1 = downstream1.combiner().apply(acc1, other.acc1);
acc2 = downstream2.combiner().apply(acc2, other.acc2);
return this;
}
R applyMerger() {
R1 r1 = downstream1.finisher().apply(acc1);
R2 r2 = downstream2.finisher().apply(acc2);
return merger.apply(r1, r2);
}
}
return Collector.of(Acc::new, Acc::accumulate, Acc::combine, Acc::applyMerger);
}
Please note that I’m not considering the characteristics of the downstream collectors when creating the returned collector.