2017-05-30 15 views
3

请允许我提出一些抱怨,也许它是无聊的,但我想描述:“为什么会提出这个问题?”。 昨天晚上我回答了不同的问题here,herehere为什么Stream操作与收集器重复?

后,我得到钻研它,我发现有StreamCollector违反Don't repeat yourself原则,e.g之间有许多重复的逻辑:在JDK-9和.etc Stream#map & Collectors#mappingStream#filter & Collectors#filtering

但似乎合理的,因为Stream遵守Tell, Don't ask原理/ Law of DemeterCollector通过Composition over Inheritance遵守的原则。

为什么Stream操作与Collector重复我只能想到的几个原因S作为如下:

  1. 我们不关心的Stream是如何在一个大的背景下产生。在这种情况下Stream操作更有效和比Collector更快,因为它可以映射Stream到另一个Stream简单地,例如:

    consuming(stream.map(...)); 
    consuming(stream.collect(mapping(...,toList())).stream()); 
    
    void consuming(Stream<?> stream){...} 
    
  2. Collector是更强大,罐构成Collectorš在一起以收集元件在流但是,Stream仅提供一些有用/高度使用的操作。例如:

    stream.collect(groupingBy(
        ..., mapping(
         ..., collectingAndThen(reducing(...), ...) 
         ) 
    )); 
    
  3. Stream操作比Collector更表现做一些简单的工作的时候,但他们更慢于Collector小号,因为它会为每个操作创建一个新的数据流和Stream比更重的和抽象Collector。例如:

    stream.map(...).collect(collector); 
    stream.collect(mapping(..., collector)); 
    
  4. Collector不能施加短路端子操作Stream。例如:

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

有谁可以想出其他不利因素/优势为什么流业务被复制在这里收藏家?我想重新理解它们。提前致谢。

+0

因为这是他们设计它的方式。如果您有投诉,请提交错误报告或改进请求,或者聘请一个大厅。 – EJP

+3

另请参见[Collectors.summingInt()vs mapToInt().sum()](https://stackoverflow.com/q/37023822/2711488) – Holger

+0

@Holger感谢您的链接,我花费大部分时间来理解因为我不擅长英语。 –

回答

7

链接专用终端流操作可能被认为更多用于链接方法调用的表达方式,而不是构成收集器工厂调用的“LISP风格”。但是它也为流实现提供了优化执行策略,因为它知道实际的操作,而不是仅仅看到抽象。另一方面,当你自己命名时,可以编写Collector s,允许在不可能再进行流操作的地方执行嵌入另一个收集器的这些操作。我想,这种镜像只会在Java 8开发的后期阶段才会显现出来,这就是为什么一些操作缺乏对应的原因,如filteringflatMapping,它们只会在Java 9中出现。因此,有两个不同的API在做类似的事情,不是在开发开始时做出的设计决定。

+2

我从来没有说过“LISP风格”是不合理的。我所说的是,Java开发人员更习惯于链式调用风格。 – Holger

+0

非常感谢。 –

+1

@Holger如果你是对的,那么这是非常有意义的,考虑到java-8当时的迟到时间...... – Eugene

6

Collectors方法似乎重复Stream方法提供额外的功能。当与其他Collector组合使用时,它们是有意义的。

例如,如果我们考虑Collectors.mapping(),最常见的用法是将它传递给Collectors.groupingByCollector

考虑这个例子(从Javadoc中取出):

List<Person> people = ... 
Map<City, Set<String>> namesByCity 
     = people.stream().collect(groupingBy(Person::getCity, TreeMap::new, 
               mapping(Person::getLastName, toSet()))); 

mapping这里用于转化各组的值Collection的元素类型从PersonString

没有它(和toSet()Collector)输出将是Map<City, List<Person>>。现在

,你当然可以map一个Stream<Person>Stream<String>使用people.stream().map(Person::getLastName),但随后你将通过PersonPerson::getCity在这个例子中)一些其他财产损失的能力,这些群体姓氏。

+0

先生,非常感谢。我发现我在第二个问题中描述了它。但是我的太宽泛了。 –