为什么收集器接口的合并器与重载收集方法不一致?

2022-09-02 01:31:28

接口中有一个重载方法 ,具有以下签名:collect()Stream<T>

<R> R collect(Supplier<R> supplier,
          BiConsumer<R,? super T> accumulator,
          BiConsumer<R,R> combiner)

还有 另一个版本 ,它接收具有前三个函数的对象。对应于 的接口的属性具有 签名 。collect(Collector<? super T,A,R> collector)CollectorcombinerBinaryOperator<A> combiner()

在后一种情况下,Java API 8 指出:

合并器函数可以将状态从一个参数折叠到另一个参数并返回该参数,或者可以返回新的结果容器。

为什么前一种方法也不收到?collectBinaryOperator<R>


答案 1

的 “内联”(3-arg)版本专为您已经拥有这些功能“躺着”而设计。例如:collect

ArrayList<Foo> list = stream.collect(ArrayList::new, 
                                     ArrayList::add,
                                     ArrayList::addAll);

BitSet bitset = stream.collect(BitSet::new, 
                               BitSet::set,
                               BitSet::or);

虽然这些只是激励性的例子,但我们对类似的现有构建器类的探索是,现有组合器候选者的签名更适合转换为BiConsumer而不是BinaryOperator。提供你所要求的“灵活性”将使这种过载在它旨在支持的情况下变得不那么有用 - 也就是说,当你已经拥有功能时,你不想制造(或学习制作)收集器只是为了收集它们。

另一方面,收集器具有更广泛的用途,因此值得额外的灵活性。


答案 2

请记住,的主要目的是支持可变缩减。对于此操作,累加器合并器这两个函数都旨在操作可变容器,并且不需要返回值。Stream.collect()

因此,不坚持返回值要方便得多。正如Brian Goetz所指出的那样,这一决定允许重用许多现有的容器类型及其方法。如果没有直接使用这些类型的能力,整个三参数方法将毫无意义。collect

相比之下,该接口是此操作的抽象,支持更多的用例。最值得注意的是,您甚至可以通过收集器对具有值类型(或具有值类型语义的类型)的普通(即非可变)约简操作进行建模。在这种情况下,必须有一个返回值,因为值对象本身不得修改。Collector

当然,它并不意味着用作 代替 。相反,这种抽象在组合收集器时会派上用场,例如.stream.collect(Collectors.reducing(…))stream.reduce(…)groupingBy(…,reducing(…))


推荐