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

Java 为什么收集器接口的组合器与重载的collect方法不一致?,java,java-8,java-stream,Java,Java 8,Java Stream,在接口Stream中有一个重载方法,collect(),具有以下签名: <R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner) R收集(供应商、, 双消费者累加器, 双消费组合器) 还有另一个版本的collect(Collector,collect的“内联”(3-a

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

<R> R collect(Supplier<R> supplier,
          BiConsumer<R,? super T> accumulator,
          BiConsumer<R,R> combiner)
R收集(供应商、,
双消费者累加器,
双消费组合器)
还有另一个版本的
collect(Collector,
collect
的“内联”(3-arg)版本是为您已经拥有这些功能的情况而设计的。例如:

ArrayList<Foo> list = stream.collect(ArrayList::new, 
                                     ArrayList::add,
                                     ArrayList::addAll);
虽然这些只是令人振奋的例子,但我们对类似现有构建器类的探索是,现有组合器候选项的签名更适合转换为双consumer,而不是BinaryOperator。提供了“灵活性”如果您要求使用,则会使此重载在其设计支持的情况下远没有那么有用——也就是说,您已经拥有了可用的函数,并且不想为了收集它们而制作(或学习制作)收集器


另一方面,收集器的使用范围要广得多,因此具有额外的灵活性。

如果前一个
collect
方法接收到
BinaryOperator
,则以下示例将无法编译:

ArrayList<Foo> list = stream.collect(ArrayList::new, 
                                     ArrayList::add,
                                     ArrayList::addAll);
ArrayList list=stream.collect(ArrayList::new,
ArrayList::add,
ArrayList::addAll);
在这种情况下,编译器无法推断
组合器的返回类型,并将给出编译错误


因此,如果此版本的
collect
方法与
Collector
接口一致,那么它将促进此版本的
collect
方法的更复杂的使用,这并非本意。

请记住
Stream.collect()的主要目的
支持。对于此操作,累加器和组合器这两个函数都用于操作可变容器,不需要返回值

因此,不坚持返回值要方便得多。因为,此决定允许重用许多现有容器类型及其方法。如果不能直接使用这些类型,则整个三个arg
collect
方法将毫无意义

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


当然,它并不是要用作
stream.collect(收集器.reduce(…)
,而不是
stream.reduce(…)
。相反,这种抽象在组合收集器时非常方便,例如
groupingBy(…),reduce(…)

关于collect的另一个问题-
StringBuilder::append
是一个不好的例子,因为它确实返回了容器。但这将是一个很好的候选者。感谢@Holger,已修复。看起来
combiner
的内联版本的文档缺少一个关键细节:哪一方应该接收合并的结果?二进制文件YoOperator版本可以让实现者自己决定,但双消费者需要指定哪个是主要的。
ArrayList<Foo> list = stream.collect(ArrayList::new, 
                                     ArrayList::add,
                                     ArrayList::addAll);