为什么Collector接口的组合器与重载的collect方法不一致?
在接口Stream
有一个带有以下签名的重载方法collect()
:
R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)
还有另一个版本的collect(Collector collector)
,它接收具有前三个函数的对象。 与combiner
Collector
对应的接口Collector
的属性具有签名BinaryOperator combiner()
。
在后一种情况下,Java API 8声明:
组合器函数可以将状态从一个参数折叠到另一个参数并返回该参数,或者可以返回新的结果容器。
为什么前者collect
方法也没有收到BinaryOperator
?
“inline”(3-arg)版本的collect
是专为你已经“躺着”的这些function而设计的。 例如:
ArrayList list = stream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
要么
BitSet bitset = stream.collect(BitSet::new, BitSet::set, BitSet::or);
虽然这些仅仅是激励性的例子,但我们对类似的现有构建器类的探索是,现有组合器候选者的签名更适合转换为BiConsumer而不是BinaryOperator。 提供你所要求的“灵活性”会使这种过载在它被设计为支持的情况下变得不那么有用 – 也就是说,当你已经有了function,并且你不想做(或者学习制作)collections家只是为了收集它们。
另一方面,收集器具有更广泛的用途,因此具有额外的灵活性。
请记住, Stream.collect()
的主要目的是支持Mutable Reduction 。 对于此操作,两个函数, 累加器和组合器都旨在操纵可变容器,而不需要返回值。
因此,不坚持返回值更方便。 正如Brian Goetz指出的那样 ,这个决定允许重复使用许多现有的容器类型及其方法。 如果没有直接使用这些类型的能力,整个三参数collect
方法将毫无意义。
相反, Collector
接口是此操作的抽象 ,支持更多用例。 最值得注意的是,您甚至可以通过Collector
为值类型(或具有值类型语义的类型)建模普通的,即非可变的Reducing操作。 在这种情况下, 必须有返回值,因为不能修改值对象本身。
当然,它并不意味着用作stream.collect(Collectors.reducing(…))
而不是stream.reduce(…)
。 相反,这种抽象在组合收集器时很方便,例如groupingBy(…,reducing(…))
。
如果前一个collect
方法收到BinaryOperator
则以下示例将无法编译:
ArrayList list = stream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
在这种情况下,编译器无法推断combiner
的返回类型,并会产生编译错误。
因此,如果此版本的collect
方法与Collector
接口一致,那么它将促使更复杂地使用此版本的collect
方法,这不是预期的。