聚合操作如何在Java流上工作?

聚合操作如何在Java流上工作?,java,data-structures,collections,java-stream,Java,Data Structures,Collections,Java Stream,在下面的摘录中,我们将这些人的名字映射到他们的性别 Map<Person.Sex, List<String>> namesByGender = roster .stream() .collect( Collectors.groupingBy( Person::getGender, Collectors.mapping(

在下面的摘录中,我们将这些人的名字映射到他们的性别

Map<Person.Sex, List<String>> namesByGender =
roster
    .stream()
    .collect(
        Collectors.groupingBy(
            Person::getGender,                      
            Collectors.mapping(
                Person::getName,
                Collectors.toList())));
按性别映射名称=
名册
.stream()
.收集(
收集者分组(
Person::getGender,
图(
Person::getName,
收藏家;
我了解收集操作:
1) 根据getGender的结果对流中的每个人进行分组。
2) 将每个人映射到getName的结果。
3) 从结果和列表中形成一个列表。
4) 生成一个地图,其关键字为人员的性别,数据值为人员的姓名

我的问题是:
1) 收集者的行为顺序是什么?

2) 它们之间的间歇类型是什么?

如果我们查看
groupingBy的
来源,我们将看到以下内容:

Supplier<A> downstreamSupplier = downstream.supplier();
        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
            downstreamAccumulator.accept(container, t);
        };
供应商下游供应商=下游供应商();
双消费下游累加器=下游累加器();
双消费累加器=(m,t)->{
K key=Objects.requirennull(分类器.apply(t),“元素不能映射到空键”);
A container=m.computeIfAbsent(key,k->downstreamSupplier.get());
下游累积器接收(容器,t);
};
首先。计算键调用
Person::getGender

第二。如果密钥不存在,则创建新的下游容器
ArrayList::new

第三,。Add元素从
Person::getName
返回到容器
List::Add


ArrayList::new
List::add
如果我们查看
收集器,可以找到
CollectorImpl
构造函数的参数。toList
方法收集器不“动作”,因此不按顺序动作。这不像一个采集器在使用间歇类型将数据传递给另一个采集器之前处理所有数据

您正在用这些工厂组成一个收集器,它将在传递到
Stream.collect
时一次完成全部工作

正如秘书长解释的那样:

收集器由四个函数指定,这些函数一起工作,将条目累积到可变结果容器中,并可以选择对结果执行最终转换。它们是:

  • 创建新的结果容器(supplier())
  • 将新数据元素合并到结果容器(累加器())
  • 将两个结果容器合并为一个(合并器())
  • 在容器(finisher())上执行可选的最终转换
因此,
toList()
收集器可以像供应商一样简单地实现,
ArrayList::new
List::add
作为累加器和
List::addAll
作为组合器,而不需要自定义的finisher,这就是它在参考实现中的实现方式,但这是一个实现细节,允许其他实现

然后,使用指定的下游收集器组合新收集器,并通过首先应用指定的映射器函数并将其结果传递给原始累加器函数来装饰其累加器函数。结果还是一个由四个函数组成的收集器。在collect操作期间,映射器函数将在添加到列表之前应用于每个元素

最后,将做一个更复杂的组成。供应商将创建一个新映射,通常是
HashMap
。累加器将使用类似于
map.computeIfAbsent
的操作评估分组函数并将结果存储到映射中,该操作将评估下游收集器的供应商(如果密钥是新的),然后应用下游收集器的累加器函数,这是场景中的组合函数。组合器函数设置为
Map。如果只有一个Map包含键,则使用任一Map的值进行合并,如果两个Map中都存在键,则使用下游的组合器进行合并

因此,组合采集器的处理包括对指定函数的交错处理,而不是一个接一个地处理采集器。换句话说,对于顺序执行,操作将等效于

Map<Person.Sex, List<String>> namesByGender = new HashMap<>();
for(Person p: roster)
    namesByGender.computeIfAbsent(p.getGender(), k -> new ArrayList()).add(p.getName());
Map namesByGender=new HashMap();
人员(p:名册)
namesByGender.computeIfAbsent(p.getGender(),k->new ArrayList()).add(p.getName());