Collectors.teeing()是Java 12引入的并行双收集工具,支持单次遍历中用两个独立收集器处理同一元素,并通过合并函数整合结果,提升多维度聚合效率。

Java Stream API 中的 Collectors.teeing() 是 Java 12 引入的实用工具,它让你能在一次流遍历中并行执行两个收集操作,并把结果合并成一个定制对象。不用重复过滤、不需手动拼接,逻辑更清晰、性能更优。
teeing() 的核心作用
它不是“先做A再做B”,而是“同一个元素同时喂给两个收集器”,最后用合并函数缝合结果。这避免了多次流处理带来的开销,尤其适合需要多维度聚合的场景。
- 每个元素只被访问一次,提升效率
- 两个下游收集器完全独立,可自由组合(比如
toList()和counting()) - 合并函数灵活,可返回任意类型(String、自定义类、Map 等)
基本用法结构
调用格式固定为三部分:第一个收集器、第二个收集器、合并函数。
-
第一个收集器:例如
Collectors.toList()、Collectors.summingInt(Person::age) -
第二个收集器:例如
Collectors.counting()、Collectors.maxBy(Comparator.comparing(Person::age)) -
合并函数:用
(r1, r2) -> new Result(r1, r2)或字符串拼接等方式整合
典型使用场景
常见需求几乎都能用 teeing() 更优雅地表达:
立即学习“Java免费学习笔记(深入)”;
- 统计符合条件的列表 + 同时计算总数(如“报名名单”和“总人数”)
- 求最大值与最小值(单次遍历完成,比两次
maxBy/minBy更高效) - 分组后分别统计数量和平均值(如按城市分组,每组返回
count和avgSalary) - 筛选出对象列表的同时汇总某个字段(如选出所有电动车,同时算出它们的总续航)
一个简洁示例:找年龄极值
给定 List<Person>,想一次性拿到最小年龄和最大年龄的完整信息:
var result = people.stream().collect(
Collectors.teeing(
Collectors.minBy(Comparator.comparingInt(Person::age)),
Collectors.maxBy(Comparator.comparingInt(Person::age)),
(min, max) -> "Min: " + min.orElse(null) + ", Max: " + max.orElse(null)
)
);
注意:minBy 和 maxBy 返回 Optional,合并时建议用 orElse 或 map(...).orElse(null) 处理空值,避免运行时异常。
不复杂但容易忽略:teeing() 的两个下游收集器必须兼容输入类型,且合并函数要能正确处理可能的 null 值。用对了,能让代码从“能跑”变成“干净又高效”。


















