Java Stream API:探究 Collectors.teeing () 收集器

Java 12中引入的Collector.teeing特性是对Java流API中Collector接口的一个强大补充。

teeing()方法

teeing()Collectors类的一个静态方法,用于返回一个将两个Collector操作的结果组合起来的Collector。传递给生成的收集器的每个元素都会由两个下游收集器进行处理,然后使用指定的合并函数将它们的结果合并为最终结果。

语法

public static <T, R1, R2, R> Collector<T,?, R> teeing(
    Collector<? super T,?, R1> downstream1,
    Collector<? super T,?, R2> downstream2,
    BiFunction<? super R1,? super R2, R> merger
)

说明

Collector.teeing方法接受三个参数:

  • • Collector<? super T,?, R1> downstream1:第一个下游收集器,用于从流中收集元素。
  • • Collector<? super T,?, R2> downstream2:第二个下游收集器,同样用于从流中收集元素。
  • • BiFunction<? super R1,? super R2, R> merger:用于合并第一个和第二个收集器结果的合并函数。

生成的收集器函数执行以下操作:

  • • supplier(供应器):创建一个结果容器,其中包含通过调用每个收集器的供应器获得的结果容器。
  • • accumulator(累加器):使用其结果容器和输入元素调用每个收集器的累加器。
  • • combiner(组合器):使用两个结果容器调用每个收集器的组合器。
  • • finisher(完成器):使用其结果容器调用每个收集器的完成器,然后调用提供的合并函数并返回其结果。

如果两个下游收集器都是无序的,那么生成的收集器具有Collector.Characteristics.UNORDERED特性;如果两个下游收集器都是并发的,那么生成的收集器具有Collector.Characteristics.CONCURRENT特性。

示例代码

我们考虑这样一个场景,有一个Person对象的列表。

record Person(String name, String city, int age){}

示例1:从Person对象列表中找出最小和最大年龄。

public static void main(String[] args) {

        List<Person> people = List.of(new Person("Alex", "Paris", 32),
                new Person("Martin", "Paris", 24),
                new Person("Tim", "Paris", 23),
                new Person("Emilie", "Berlin", 25),
                new Person("Albert", "Chicago", 24),
                new Person("Mateo", "Madrid", 25),
                new Person("Adrien", "Barcelone", 27));

        var minMaxAge = people.stream().collect(
                Collectors.teeing(
                        Collectors.minBy(Comparator.comparingInt(Person::age)),
                        Collectors.maxBy(Comparator.comparingInt(Person::age)),
                        (min, max) -> "Min = " + min.get() + ", Max = " + max.get() // 合并
                )
        );
        System.out.println(minMaxAge);
    }
输出:

Min = Person[name=Tim, city=Paris, age=23], Max = Person[name=Alex, city=Paris, age=32]

示例1:找出居住在巴黎的人员列表以及年龄为24岁的人员列表

public static void main(String[] args) {

        List<Person> people = List.of(new Person("Alex", "Paris", 32),
                new Person("Martin", "Paris", 24),
                new Person("Tim", "Paris", 23),
                new Person("Emilie", "Berlin", 25),
                new Person("Albert", "Chicago", 24),
                new Person("Mateo", "Madrid", 25),
                new Person("Adrien", "Barcelone", 27));

        List<List<Person>> result = people.stream()
                .collect(Collectors.teeing(
                        Collectors.filtering(p -> p.city().equals("Paris"),
                                Collectors.toList()),
                        Collectors.filtering(p -> 24 == p.age(),
                                Collectors.toList()),
                        List::of
                ));

        System.out.println(result);
    }
输出:
 [[Person[name=Alex, city=Paris, age=32], 
  Person[name=Martin, city=Paris, age=24], 
  Person[name=Tim, city=Paris, age=23]],

 [Person[name=Martin, city=Paris, age=24],
 Person[name=Albert, city=Chicago, age=24]]]

示例1:统计居住在巴黎的人数以及流中发出的人员数量

public static void main(String[] args) {

        List<Person> people = List.of(new Person("Alex", "Paris", 32),
                new Person("Martin", "Paris", 24),
                new Person("Tim", "Paris", 23),
                new Person("Emilie", "Berlin", 25),
                new Person("Albert", "Chicago", 24),
                new Person("Mateo", "Madrid", 25),
                new Person("Adrien", "Barcelone", 27));

        List<Long> result = people.stream()
                .collect(Collectors.teeing(
                        Collectors.filtering(p -> p.city().equals("Paris"),
                                Collectors.counting()),
                        Collectors.counting(),
                        List::of)
                );

        System.out.println(result);
}
输出:
[3, 7]

结论

Collectors.teeing()方法是一个强大的工具,用于在一次遍历中执行多个流操作,使你的代码更加高效且富有表现力。

 

请登录后发表评论

    没有回复内容