为什么java.util.Collection没有实现新的Stream接口?
我花了一些时间开始研究关于stream和lambdas的java-8嗡嗡声。 让我吃惊的是,你不能直接在java.util.Collection
上应用Stream操作,比如.map()
.filter()
。 是否有一个技术原因,为什么java.util.Collection
接口没有扩展这些stream操作的默认实现?
使用Googlesearch一下,我看到很多例子都是按照以下模式进行编码的:
List<String> list = someListExpression; List<String> anotherList = list.stream().map(x -> f(x)).collect(Collectors.toList());
如果你在你的代码中有很多这样的stream操作,就会变得非常笨拙。 由于.stream()
和.collect()
与你想expression的内容完全无关,所以你更愿意说:
List<String> list = someListExpression; List<String> anotherList = list.map(x -> f(x));
是的,这些决定有很好的理由:)
关键是急于和懒惰的操作之间的区别。 您在第一个问题下给出的示例显示了映射或过滤列表的热切操作会生成新列表。 这没什么不对,但往往不是你想要的,因为你经常在做比你需要的更多的工作。 一个急切的操作必须对每一个元素进行操作,并产生一个新的集合。 如果你正在编写多个操作(filter-map-reduce),那么你正在做很多额外的工作。 另一方面,懒惰的行动构成精美; 如果你这样做:
Optional<Person> tallestGuy = people.stream() .filter(p -> p.getGender() == MALE) .max(comparing(Person::getHeight));
filter和减less(最大)操作融合在一起成为一个单一的过程。 这非常有效。
那么,为什么不直接在List上暴露Stream方法呢? 那么我们就这样试了。 在许多其他原因中,我们发现像filter()
这样的惰性方法和像removeAll()
这样的急切方法混淆了用户。 通过将懒惰方法分组成一个单独的抽象,它变得更清晰; List
上的方法是那些改变列表的方法; Stream
上的方法是那些处理数据序列的可组合的惰性操作,而不pipe数据在哪里存在。
所以,如果你想要做简单的事情,那么你build议的方式是很好的,但是当你试图build立它时,它会开始崩溃。 额外的stream()
方法是否令人讨厌? 当然。 但是保持数据结构(主要是关于在内存中组织数据)和stream(主要是关于组合集合行为)的抽象,将更好地分解为更复杂的操作。
对于你的第二个问题,你可以做到这一点比较容易:实现像这样的stream方法:
public<U> Stream<U> map(Function<T,U> mapper) { return convertToStream().map(mapper); }
但这只是逆stream而上。 最好只实现一个有效的stream()方法。