为什么 Stream 操作与 Collectors 重复?

2022-01-22 00:00:00 java-8 java java-stream

请允许我提出一些抱怨,也许这很无聊,但我想描述一下:为什么会提出这个问题?".我回答的问题不同于其他人这里, 这里和这里昨晚.

Please allow me to make some complaints, maybe it is boringly but I want to describe:"Why did this question will be raised?". I have answered questions is different from others here, here and here last night.

深入研究后,我发现 流 和 不重复自己原则的nofollow noreferrer">收集器,例如:流#map &Collectors#mapping, Stream#filter &Collectors#filtering in jdk-9 and .etc.

After I get dig into it, I found there are many duplicated logic between Stream and Collector that violates Don't repeat yourself principle, e.g: Stream#map & Collectors#mapping, Stream#filter & Collectors#filtering in jdk-9 and .etc.

但这似乎是合理的,因为 Stream 遵守告诉,不要问 原则/得墨忒耳法则 和 Collector 遵守 组合优于继承原则.

But it seems to reasonable since Stream abide by Tell, Don't ask principle/Law of Demeter and Collector abide by Composition over Inheritance principle.

我只能想到几个原因 Stream 操作与 收藏家如下:

I can only think of a few reasons why Stream operations is duplicated with Collectors as below:

  1. 我们不关心 Stream 是在大上下文中创建的.在这种情况下 Stream 操作是比 Collector 更有效、更快因为它可以映射一个 Stream到另一个 Stream 简单地,对于示例:

  1. We don't care of how the Stream is created in a big context. in this case Stream operation is more effectively and faster than Collector since it can mapping a Stream to another Stream simply, for example:

consuming(stream.map(...));
consuming(stream.collect(mapping(...,toList())).stream());

void consuming(Stream<?> stream){...}

  • 收集器 更强大,可以编写Collectors 一起收集流中的元素,但是,Stream 只提供一些有用/高度使用的操作.例如:

  • Collector is more powerful that can composes Collectors together to collecting elements in a stream, However, Stream only providing some useful/highly used operations. for example:

    stream.collect(groupingBy(
      ..., mapping(
            ..., collectingAndThen(reducing(...), ...)
           )
    ));
    

  • 流 操作比 Collector 在做一些简单的工作时,但它们比 Collectors,因为它会为每个操作和 Stream 比 收集器.例如:

  • Stream operations is more expressiveness than Collector when doing some simpler working, but they are more slower than Collectors since it will creates a new stream for each operation and Stream is more heavier and abstract than Collector. for example:

    stream.map(...).collect(collector);
    stream.collect(mapping(..., collector));
    

  • 收集器 不能将短路终端操作应用为 流.例如:

  • Collector can't applying short-circuiting terminal operation as Stream. for example:

    stream.filter(...).findFirst();
    

  • 有没有人可以提出其他缺点/优点,为什么 Stream 操作在这里与 Collectors 重复?我想重新理解他们.提前致谢.

    Does anyone can come up with other disadvantage/advantage why Stream operations is duplicated with Collectors here? I'd like to re-understand them. Thanks in advance.

    推荐答案

    对于那些习惯于链接方法调用的人来说,链接一个专用的终端流操作可能比组合收集器工厂调用的LISP 风格"更具表现力.但它也允许优化流实现的执行策略,因为它知道实际操作,而不仅仅是看到 Collector 抽象.

    Chaining a dedicated terminal stream operation might be considered more expressive by those being used to chained method calls rather than the "LISP style" of composed collector factory calls. But it also allows optimized execution strategies for the stream implementation, as it knows the actual operation instead of just seeing a Collector abstraction.

    另一方面,正如您自己命名的那样,Collector 可以组合在一起,允许在不再可能进行流操作的地方执行嵌入在另一个收集器中的这些操作.我想,这种镜像仅在 Java 8 开发的后期才变得明显,这就是为什么某些操作缺少对应的操作,例如 filteringflatMapping,这将仅在 Java 9 中存在.因此,让两个不同的 API 做类似的事情,并不是在开发之初就做出的设计决定.

    On the other hand, as you named it yourself, Collectors can be composed, allowing to perform these operation embedded in another collector, at places where stream operations are not possible anymore. I suppose, this mirroring become apparent only at a late stage of the Java 8 development, which is the reason why some operations lacked their counterpart, like filtering or flatMapping, which will be there only in Java 9. So, having two different APIs doing similar things, was not a design decision made at the start of the development.

    相关文章