为什么java.util.Collection没有实现新的Stream接口?

时间:2014-06-29 01:08:36

标签: java lambda functional-programming java-8 java-stream

我花了一些时间开始研究关于stream和lambdas的java-8嗡嗡声。让我感到惊讶的是,您无法直接在.map()上应用Stream操作,例如.filter()java.util.Collection。是否有技术原因导致java.util.Collection接口没有扩展 这些Stream操作的默认实现?

谷歌搜索了一下,我看到很多人按照以下模式编码的例子:

List<String> list = someListExpression;
List<String> anotherList = list.stream().map(x -> f(x)).collect(Collectors.toList());
如果您的代码中有很多这些流操作,那么

会变得非常笨拙。由于.stream().collect()与您想要表达的内容完全无关,因此您更愿意说:

List<String> list = someListExpression;
List<String> anotherList = list.map(x -> f(x));

1 个答案:

答案 0 :(得分:85)

是的,这些决定有很好的理由:)

关键是渴望懒惰操作之间的区别。您在第一个问题下给出的示例显示了急切的操作,其中映射或过滤列表会生成新列表。这没有什么不对,但它往往不是你想要的,因为你经常做的工作比你需要的多;渴望的操作必须对每个元素进行操作,并产生新的集合。如果你正在编写多个操作(filter-map-reduce),那么你需要做很多额外的工作。另一方面,懒惰的操作组合得很漂亮;如果你这样做:

Optional<Person> tallestGuy = people.stream()
                                    .filter(p -> p.getGender() == MALE)
                                    .max(comparing(Person::getHeight));

过滤器和reduce(max)操作融合在一起。这非常有效。

那么,为什么不直接在List上公开Stream方法呢?好吧,我们就这样试过了。在众多其他原因中,我们发现混合惰性方法(如filter())和急切方法(如removeAll())会让用户感到困惑。通过将惰性方法分组为单独的抽象,它变得更加清晰; List上的方法是那些改变列表的方法; Stream上的方法是那些处理数据序列的可合并,懒惰操作的方法,无论数据存在于何处。

所以,如果你想做一些非常简单的事情,你建议它的方式很好,但是当你试图在它上面构建时,它会开始分崩离析。额外的stream()方法是否烦人?当然。但是,保持数据结构的抽象(主要是关于在内存中组织数据)和流(主要是关于组合聚合行为)将更好地扩展到更复杂的操作。

关于第二个问题,你可以相对容易地做到这一点:实现像这样的流方法:

public<U> Stream<U> map(Function<T,U> mapper) { return convertToStream().map(mapper); }

但那只是逆流而上;最好只实现一个有效的stream()方法。