collectors.teeing支持单次遍历并行执行两个聚合操作并合并结果,接收两个下游收集器和一个bifunction合并函数,适用于求和+平均值、最值+频次等场景,需注意空值处理与并发安全。

Java 12 引入的 Collectors.teeing 是一个非常实用的收集器,它允许你对同一个流**并行执行两个独立的聚合操作**,最后将两个结果合并为一个最终值。它解决了“不想两次遍历流、又需要多种统计结果”的典型痛点。
teeing 的基本结构和用法
Collectors.teeing 接收三个参数:第一个和第二个是用于分流处理的收集器(比如 Collectors.summingInt、Collectors.maxBy),第三个是一个 BiFunction,用来合并这两个收集器的结果。
语法形式:
Collectors.teeing(
downstream1, // 第一个收集器
downstream2, // 第二个收集器
(result1, result2) -> {...} // 合并逻辑
)
常见组合示例:求和 + 平均值
比如统计一组整数的总和与平均值(注意:平均值需转为 double 避免整数除法):
- 第一个收集器用
Collectors.summingInt(x -> x)得到总和 - 第二个收集器用
Collectors.averagingInt(x -> x)直接得平均值 - 合并函数可直接返回
new AbstractMap.SimpleEntry(sum, avg)或自定义对象
代码片段:
List<integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
var result = numbers.stream()
.collect(Collectors.teeing(
Collectors.summingInt(Integer::intValue),
Collectors.averagingInt(Integer::intValue),
(sum, avg) -> Map.of("sum", sum, "avg", avg)
));</integer>
输出:{sum=15, avg=3.0}
更灵活的场景:最大值 + 最小值 + 出现次数
想同时获取最大值、最小值,以及最大值出现的次数?可以这样组合:
- 下游1:用
Collectors.maxBy(Comparator.naturalOrder())得 Optional - 下游2:用
Collectors.groupingBy(Function.identity(), Collectors.counting())得频率映射 - 合并时从频率映射中查出最大值对应的计数
关键点:下游收集器可以是任意复杂类型(Map、Optional、自定义类),只要合并函数能处理即可。
注意事项和避坑点
teeing 虽然方便,但要注意几个实际细节:
- 两个下游收集器是**独立并行执行**的,不会共享中间状态 —— 所以不能依赖顺序或副作用
- 如果某个下游收集器可能返回 null(如
maxBy对空流返回 empty Optional),合并函数要判空,否则会 NPE - 不支持并发流下的线程安全自动保障 —— 若下游收集器本身不是并发安全的(如
Collectors.toList()),在 parallelStream 中需改用Collectors.toConcurrentMap等替代 - 性能上仍是单次遍历,但每个元素会被传给两个收集器 —— 内存和计算开销略高于单个收集器,但远优于两次 collect
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











