当前位置: 首页 > 面试题库 >

为什么流操作与收集器重复?

颜霖
2023-03-14
问题内容

在深入研究之后,我发现Stream和Collector之间存在许多重复的逻辑,这些逻辑违反了不要重复自己的原则,例如:jdk-9和中的Stream#map&Collectors#mapping,Stream#filter&Collectors#filtering。等等

但自从溪流遵守告诉,不要问得墨meter耳的法则/
得墨Law律和集热器遵守继承构成原则看来,这是合理的。

我只能想到以下几个原因,为什么用Collector重复Stream操作:

  1. 我们不在乎在大环境中如何创建Stream。在这种情况下,Stream操作比Collector更有效和更快,因为它可以简单地将Stream映射到另一个Stream,例如:
        consuming(stream.map(...));
    consuming(stream.collect(mapping(...,toList())).stream());

    void consuming(Stream<?> stream){...}
  1. Collector更强大,可以将Collector组合在一起,以收集流中的元素,但是,Stream仅提供一些有用/经常使用的操作。例如:

    stream.collect(groupingBy(
    

    …, mapping(
    …, collectingAndThen(reducing(…), …)
    )
    ));

  2. 当执行一些更简单的工作时,Stream操作比Collector更具表达性,但它们比Collector慢得多,因为它将为每个操作创建一个新的Stream,并且Stream比Collector更加繁重和抽象。例如:

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

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

  3. 收集器不能将短路端子操作用作Stream。例如:

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

有谁能提出其他缺点/优势,为什么在此处使用收集器复制Stream操作?我想重新理解它们。提前致谢。


问题答案:

链接专用终端流操作可能会被那些用于链接方法调用的人表示,而不是组成收集器工厂调用的“
LISP风格”,更具表达性。但它也允许针对流实现的优化执行策略,因为它知道实际的操作,而不仅仅是看到Collector抽象。

另一方面,正如您自己命名的那样,Collector可以组成s,从而允许在不再可能进行流操作的位置执行嵌入到另一个收集器中的这些操作。我想,这种镜像仅在Java
8开发的后期才变得明显,这就是为什么某些操作缺少对应的操作(如filteringor )的原因,而这些操作flatMapping仅在Java
9中才存在。因此,让两个不同的API进行相似的操作,不是在开发之初就做出的设计决定。



 类似资料:
  • 请允许我提出一些抱怨,也许是令人厌烦但我想描述的是:“为什么会提出这个问题呢?”。我昨天晚上在这里、这里、这里回答的问题和其他人不一样。 Stream operations在做一些简单的工作时比Collector更有表现力,但是它们比Collector更慢,因为它会为每个操作创建一个新的Stream,并且Stream比Collector更繁重和抽象。例如: 收集器无法将短路终端操作作为流应用。例如

  • 我正在为新手程序员编写一个库,所以我试图保持API尽可能干净。 我的库需要做的事情之一是对大量的ints或long集合执行一些复杂的计算。我的用户需要从许多场景和业务对象中计算这些值,因此我认为最好的方法是使用流来允许用户将业务对象映射到或,然后在收集器中计算这些计算。 所以与其能够做到 我必须提供这样的供应商、累加器和组合器: 这对我的新手用户来说太复杂了,而且很容易出错。 在使用或的同时,是否

  • 以下是MWE: 奇怪的是,无论我键入

  • AFAIK对流求和的唯一方法是: 这里的问题是,每次调用都会创建一个新的,而不是更改可变类型。 对于

  • 我试图理解是什么保存了对对象的引用,使得它们在执行Java流终端操作时不符合垃圾收集的条件? 这是我的测试代码 从未调用LargetObject的finalize方法。 我的想法是一旦. map(largeObject- 为什么这不会发生?也许真的可以做些什么?

  • 问题内容: 是什么决定了垃圾收集器何时真正收集?它是在一定时间之后还是在一定数量的内存用完之后发生的吗?还是还有其他因素? 问题答案: 它在确定是时候运行时运行。在世代垃圾收集器中,一种常见的策略是在第0代内存分配失败时运行收集器。也就是说,每次你分配一小块内存(大块通常直接放置在“旧”代中)时,系统都会检查gen-0堆中是否有足够的可用空间,如果没有,则运行GC释放空间以使分配成功。然后将旧数据