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

Rop*_*Rop 47 java lambda functional-programming java-8 java-stream

我花了一些时间开始研究关于流和lambdas的java-8嗡嗡声.让我吃惊的是,你不能应用流操作,例如.map(),.filter()直接上java.util.Collection.是否存在技术原因导致java.util.Collection接口未通过这些Stream操作的默认实现进行扩展?

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

List<String> list = someListExpression;
List<String> anotherList = list.stream().map(x -> f(x)).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

如果你的代码中有很多这些流操作,那就变得非常笨拙了.由于.stream()并且.collect()与您想表达的内容完全无关,您宁愿说:

List<String> list = someListExpression;
List<String> anotherList = list.map(x -> f(x));
Run Code Online (Sandbox Code Playgroud)

Bri*_*etz 88

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

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

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

过滤器和减少(最大)操作融合在一起成为一个通道.这非常有效.

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

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

对于第二个问题,您可以相对轻松地执行此操作:实现如下的流方法:

public<U> Stream<U> map(Function<T,U> mapper) { return convertToStream().map(mapper); }
Run Code Online (Sandbox Code Playgroud)

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

  • 也就是说,我会为普通收藏家的便利方法投票:例如,"Stream :: toList".但我正在评论的真正原因是感谢Brian在SO上回答这些和其他设计问题! (15认同)
  • 谢谢布莱恩 - 很清楚!仍然 - 从务实的角度来看 - 对于所有日常普通的小而简单的开发案例,你并不真正关心既不懒惰也不平行,我认为拥有一个非常有价值的东西.更简洁,通常采用的方式/ api在普通列表上应用(急切版本)"流操作"... (4认同)
  • 是的,我们将来可能会在List上考虑additional_differently named_ bulk eager operations.例如,我们在8中添加了`replaceAll`和`removeIf`,我们可能会添加更多.但我们希望避开"流"中使用的名称,以避免混淆. (3认同)