创建自定义的`Collector`

创建自定义的Collector

理解Collector是如何工作的

Collector只能在对象Stream.collect(),如果想要在数字stream中收集元素,你需要理解Collector接口。

简单的来说,Collector有4个基本组件构成。前2个组件用于收集stream流中的元素。第3个组件仅在并行stream流中需要。某些类型的collector需要第4个组件来对构建的容器做后置处理。

第一个组件用于提供收集stream流中元素所放置的容器,例如ArrayList, HashSet, HashMap等。

Creating such a container can be modeled with an instance of Supplier. This first component is called the supplier.

第二个组件用于添加stream流中元素到容器中。这个组件会被反复调用,知道stream流中的元素一个一个全部添加到容器中。

在Collector API中,这个组件是BiConsumer的实例。有2个参数:

  1. 第一个参数为容器(第一个组件所创建的)

  2. 第二个参数为stream流中的元素

This biconsumer is called the accumulator in the context of the Collector API.

这2个组件已经足以让Collector工作,但Stream API中有一个约束,使得需要更多的组件才能工作。

由于Stream API支持并行操作。 Collector API可以工作在这样的上下文:各个子stream流只能被自己Collector创建的容器所收集。

一旦所有的子stream流处理完成,就会产生数个容器(子stream流所创建)。这些容器完全相同,因为它们都是由一个组件所创建(第一个组件的Supplier)。现在你需要合并这些容器到一个容器中。因此Collector API需要第三个组件combiner,合并这些容器。

A combiner is modeled by an instance of BinaryOperator that takes two partially filled containers and returns one.

This BinaryOperator is also modeled by a BiConsumer in the collect() overloads of the Stream API.

第四个组件

The fourth component is called the finisher, and will be covered later in this part.

收集原始数据类型到Collection

特殊的数字stream流的collect(),只要前三个组件。

IntStream.collect()的三个参数:

  • Supplier实例,叫supplier

  • ObjIntConsumer实例,叫accumulator

  • BiConsumer实例,叫combiner

example

Supplier<List<Integer>> supplier                  = ArrayList::new;
ObjIntConsumer<List<Integer>> accumulator         = Collection::add;
BiConsumer<List<Integer>, List<Integer>> combiner = Collection::addAll;

List<Integer> collect =
    IntStream.range(0, 10)
             .collect(supplier, accumulator, combiner );

System.out.println("collect = " + collect);

result

collect = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

收集原始数据类型到StringBuffer

example

Supplier<StringBuffer> supplier                 = StringBuffer::new;
ObjIntConsumer<StringBuffer> accumulator        = StringBuffer::append;
BiConsumer<StringBuffer, StringBuffer> combiner = StringBuffer::append;

StringBuffer collect = 
    IntStream.range(0, 10)
             .collect(supplier, accumulator, combiner);

System.out.println("collect = " + collect);

result

collect = 0123456789

使用Collector的后置处理finisher

Collectors.collectintAndThen()

example1

Collection<String> strings =
    List.of("two", "three", "four", "five", "six", "seven", "eight", "nine",
            "ten", "eleven", "twelve");

Map<Integer, Long> histogram =
    strings.stream()
           .collect(
                   Collectors.groupingBy(
                           String::length,
                           Collectors.counting()));

Map.Entry<Integer, Long> maxValue =
    histogram.entrySet().stream()
             .max(Map.Entry.comparingByValue())
             .orElseThrow();

System.out.println("maxValue = " + maxValue);

example2

Collection<String> strings =
        List.of("two", "three", "four", "five", "six", "seven", "eight", "nine",
                "ten", "eleven", "twelve");

Function<Map<Integer, Long>, Map.Entry<Integer, Long>> finisher =
    map -> map.entrySet().stream()
              .max(Map.Entry.comparingByValue())
              .orElseThrow();

Map.Entry<Integer, Long> maxValue =
    strings.stream()
           .collect(
               Collectors.collectingAndThen(
                   Collectors.groupingBy(
                           String::length,
                           Collectors.counting()),
                   finisher
               ));

System.out.println("maxValue = " + maxValue);

使用Collectors.teeing()组合俩个Collector结果

jdk12新增Collectors.teeing()

假设你有下面记录

enum Color {
    RED, BLUE, WHITE, YELLOW
}

enum Engine {
    ELECTRIC, HYBRID, GAS
}

enum Drive {
    WD2, WD4
}

interface Vehicle {}

record Car(Color color, Engine engine, Drive drive, int passengers) implements Vehicle {}

record Truck(Engine engine, Drive drive, int weight) implements Vehicle {}

假设在车辆集合中找出所有电车和电卡车

List<Vehicle> electricVehicles = vehicles.stream()
    .collect(
        Collectors.teeing(
            Collectors.filtering(
                vehicle -> vehicle instanceof Car car && car.engine() == Engine.ELECTRIC,
                Collectors.toList()),
            Collectors.filtering(
                vehicle -> vehicle instanceof Truck truck && truck.engine() == Engine.ELECTRIC,
                Collectors.toList()),
            (cars, trucks) -> {
                cars.addAll(trucks);
                return cars;
            }));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值