请允许我提出一些投诉,也许是很生气的,但我想描述:" 为什么要提出这个问题?>"。我回答了问题与昨晚的其他问题不同。
挖掘出来后,我发现流和收藏家之间有许多重复的逻辑,违反了不重复自己的原则,例如:流#map&收集器#映射,流#过滤器&收集器#jdk-9和.etc中的过滤
,但这似乎是合理的,因为溪流遵守tell,请不要以继承原则的形式询问塞米特的原则/法律。
我只能想到流动操作与收藏家复制的一些原因:
:我们不在乎如何在大环境中创建流。在这种情况下,流操作比收集器更有效,更快,因为它可以简单地将流映射到另一个流,例如:
consuming(stream.map(...)); consuming(stream.collect(mapping(...,toList())).stream()); void consuming(Stream<?> stream){...}
收集器更强大,可以将收藏家组合在一起以在流中收集元素,但是,流只提供一些有用/高度使用的操作。例如:
stream.collect(groupingBy( ..., mapping( ..., collectingAndThen(reducing(...), ...) ) ));
流操作在做一些简单的工作时比收集器更具表现力,但是它们比收集器要慢,因为它将为每个操作创建一个新的流,而流比收藏家更重,更抽象。例如:
stream.map(...).collect(collector); stream.collect(mapping(..., collector));
收集器不能将短路终端操作作为流应用。例如:
stream.filter(...).findFirst();
有人可以提出其他缺点/优势,为什么在这里收集者复制流操作?我想重新理解它们。预先感谢。
链接专用的终端流操作可以被视为更具表现力,因为那些被用来链接方法调用的终端操作而不是组成的收藏家工厂调用的" LISP样式"。但这也允许对流实施的优化执行策略,因为它知道实际操作而不仅仅是看到Collector
抽象。
另一方面,正如您自己命名的那样,Collector
S可以组成,可以在不再无法进行流操作的地方执行这些操作嵌入另一个收集器中。我想,这种镜像只有在Java 8开发的后期才变得显而易见,这就是为什么某些操作缺乏其对应方的原因,例如filtering
或flatMapping
,只有在Java 9中才存在。类似的事情不是开发开始时做出的设计决定。
似乎复制Stream
方法的Collectors
方法提供了其他功能。与其他Collector
s结合使用时,它们很有意义。
例如,如果我们考虑Collectors.mapping()
,则最常见的用途是将其传递给Collectors.groupingBy
Collector
。
考虑此示例(取自Javadoc(:
List<Person> people = ...
Map<City, Set<String>> namesByCity
= people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
mapping(Person::getLastName, toSet())));
mapping
在这里用于将每个组的值 Collection
的元素类型从 Person
转换为 String
。
没有它(和toSet()
Collector
(输出将为Map<City, List<Person>>
。
现在,您肯定可以使用people.stream().map(Person::getLastName)
map
Stream<Person>
到Stream<String>
,但是然后您将失去通过Person
的其他某些属性(在此示例中的Person::getCity
(将这些姓氏分组的能力。