323. Java Stream API - 组合两个收集器的结果:Java 12 中的 Collectors.teeing()

文章目录

  • 323. Java Stream API - 组合两个收集器的结果:Java 12 中的 `Collectors.teeing()`
    • 📦 teeing() 方法的签名
    • 🚗🚚 实战:筛选电动车辆(Electric Vehicles)
    • 🎯 目标:
    • ✅ teeing() 示例代码
      • 💡 控制台输出:
    • 📌 分析各个部分
    • 🧠 小技巧:合并函数的替代方式
    • 🧰 teeing() 的使用场景总结
    • 📚 补充示例:求最大值与最小值

323. Java Stream API - 组合两个收集器的结果:Java 12 中的Collectors.teeing()

在 Java 12 中,Collectors工具类新增了一个强大方法:teeing()

这个方法能让我们:

同时应用两个独立的收集器(Collectors)到同一个流上,并在末尾合并它们的结果。

非常适用于并行筛选和聚合场景


📦 teeing() 方法的签名

publicstatic<T,R1,R2,R>Collector<T,?,R>teeing(Collector<?superT,?,R1>downstream1,Collector<?superT,?,R2>downstream2,BiFunction<?superR1,?superR2,R>merger)

📌 简单来说,它做了三件事:

  1. 用第一个 collector 收集数据
  2. 同时用第二个 collector 收集相同数据
  3. 用合并函数将两个结果整合为一个结果返回

🚗🚚 实战:筛选电动车辆(Electric Vehicles)

我们有一个Vehicle接口,分别由CarTruck两个类实现。

enumColor{RED,BLUE,WHITE,YELLOW}enumEngine{ELECTRIC,HYBRID,GAS}enumDrive{WD2,WD4}interfaceVehicle{}recordCar(Colorcolor,Engineengine,Drivedrive,intpassengers)implementsVehicle{}recordTruck(Engineengine,Drivedrive,intweight)implementsVehicle{}

然后,我们有如下车辆列表:

List<Vehicle>vehicles=List.of(newCar(Color.BLUE,Engine.ELECTRIC,Drive.WD2,4),newCar(Color.WHITE,Engine.HYBRID,Drive.WD4,5),newTruck(Engine.GAS,Drive.WD4,12_000),newTruck(Engine.GAS,Drive.WD2,8_000));

🎯 目标:

  • 筛选出所有电动车(Electric Engine)
    • 包括CarTruck
  • 并将它们合并成一个集合

传统方式要写两次filter(),再手动合并;使用teeing()可以一气呵成,一次遍历搞定!


✅ teeing() 示例代码

List<Vehicle>electricVehicles=vehicles.stream().collect(Collectors.teeing(// 第一个 collector:筛选电动汽车Collectors.filtering(v->vinstanceofCarcar&&car.engine()==Engine.ELECTRIC,Collectors.toList()),// 第二个 collector:筛选电动卡车Collectors.filtering(v->vinstanceofTrucktruck&&truck.engine()==Engine.ELECTRIC,Collectors.toList()),// 合并两个结果(cars,trucks)->{cars.addAll(trucks);returncars;}));System.out.println("Electric vehicles = "+electricVehicles);

💡 控制台输出:

Electricvehicles=[Car[color=BLUE,engine=ELECTRIC,drive=WD2,passengers=4]]

说明当前只有一辆电动汽车,结果正确✅。


📌 分析各个部分

位置作用
Collectors.filtering(...)对流元素进行筛选并继续收集
Collectors.toList()把筛选结果变成列表
(cars, trucks) -> { ... }用于合并两个中间结果的 BiFunction(双参数函数)

🧠 小技巧:合并函数的替代方式

如果你不想修改原始cars列表(即不可变合并),可以这样写:

(cars,trucks)->Stream.concat(cars.stream(),trucks.stream()).toList()

这样carstrucks都不被修改,返回的是新合并的结果。


🧰 teeing() 的使用场景总结

场景示例
并行筛选不同子集electric cars vs electric trucks
计算两个指标平均值 & 总和,最大值 & 最小值
多路径聚合同时 groupBy 和 count,再合并

📚 补充示例:求最大值与最小值

recordPerson(Stringname,intage){}List<Person>people=List.of(newPerson("Alice",30),newPerson("Bob",24),newPerson("Carol",35));Map.Entry<Person,Person>minMax=people.stream().collect(Collectors.teeing(Collectors.minBy(Comparator.comparingInt(Person::age)),Collectors.maxBy(Comparator.comparingInt(Person::age)),(minOpt,maxOpt)->Map.entry(minOpt.orElseThrow(),maxOpt.orElseThrow())));System.out.println("Youngest and Oldest: "+minMax);