如果您不介意使用额外的库,我们最近在jOOλ中添加了对元组收集器的支持。
Tuple2<Double, Double> avg = points.stream().collect(
Tuple.collectors(
Collectors.averagingDouble(p -> p.x),
Collectors.averagingDouble(p -> p.y)
)
);
在上面的代码中,Tuple.collectors()
将几个java.util.stream.Collector
实例组合成一个实例,将Collector
单个值收集到一个Tuple
.
这比任何其他解决方案都更加简洁和可重用。您要付出的代价是它目前在包装类型上运行,而不是在原始类型上运行double
。我想我们将不得不等到Java 10 和项目 valhalla 以实现泛型中的原始类型专业化。
如果您想自己滚动,而不是创建依赖项,相关方法如下所示:
static <T, A1, A2, D1, D2> Collector<T, Tuple2<A1, A2>, Tuple2<D1, D2>> collectors(
Collector<T, A1, D1> collector1
, Collector<T, A2, D2> collector2
) {
return Collector.of(
() -> tuple(
collector1.supplier().get()
, collector2.supplier().get()
),
(a, t) -> {
collector1.accumulator().accept(a.v1, t);
collector2.accumulator().accept(a.v2, t);
},
(a1, a2) -> tuple(
collector1.combiner().apply(a1.v1, a2.v1)
, collector2.combiner().apply(a1.v2, a2.v2)
),
a -> tuple(
collector1.finisher().apply(a.v1)
, collector2.finisher().apply(a.v2)
)
);
}
WhereTuple2
只是两个值的简单包装器。您不妨使用AbstractMap.SimpleImmutableEntry
或类似的东西。
我还在另一个 Stack Overflow 问题的回答中详细介绍了这项技术。