java.util.Collection 为啥不实现新的 Stream 接口?

Posted

技术标签:

【中文标题】java.util.Collection 为啥不实现新的 Stream 接口?【英文标题】:Why doesn't java.util.Collection implement the new Stream interface?java.util.Collection 为什么不实现新的 Stream 接口? 【发布时间】:2014-08-19 18:33:19 【问题描述】:

我刚刚花了一些时间开始研究有关流和 lambda 的 java-8 嗡嗡声。令我惊讶的是,您不能直接在java.util.Collection 上应用流操作,例如.map().filter()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】:

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

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

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

filter 和 reduce (max) 操作融合在一起成为一个单通道。这是非常有效的。

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

因此,如果您想做非常简单的事情,那么您建议的方式非常好,但是当您尝试在此基础上进行构建时开始崩溃。额外的stream() 方法烦人吗?当然。但是保持数据结构(主要是关于在内存中组织数据)和流(主要是关于组合聚合行为)的抽象分离可以更好地扩展到更复杂的操作。

对于第二个问题,您可以相对轻松地做到这一点:像这样实现流方法:

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

但这只是逆潮流而动;最好只实现一个高效的 stream() 方法。

【讨论】:

谢谢布赖恩——很好的澄清!尽管如此 - 从实用的角度来看 - 对于所有日常运行的小型和简单的开发案例,你并不真正关心既不懒惰也不关心并行性,我认为拥有一个相当有价值的在普通列表上应用(急切版本的)“流操作”的更紧凑、普遍采用的方式/api... 是的,我们将来可能会考虑对 List 进行额外的_不同名称的_批量急切操作。例如,我们在 8 中添加了replaceAllremoveIf,我们可能还会添加更多。但我们希望避免使用 Stream 中使用的名称,以避免混淆。 是否有选项可以在流操作结束时对 .collect(Collections.toList()) 方法进行编译器推断,这将有很大帮助。然而,如果可能的话,它需要一个非常非常仔细的实施。它甚至可能需要= 运算符的语言支持,然后还需要提供不同重载的能力?恐怕对 Java 的要求太高了? @BrianGoetz 基本上是询问List&lt;T&gt; newList = oldList.stream(); 是否可行,所以省略.collect(toList()) 也就是说,我会投票支持普通收集器的便捷方法:例如Stream::toList。但我发表评论的真正原因是感谢 Brian 回答了关于 SO 的这些和其他设计问题!

以上是关于java.util.Collection 为啥不实现新的 Stream 接口?的主要内容,如果未能解决你的问题,请参考以下文章

java----数据结构与算法----JavaAPI:java.util.Collection接口

java源码 -- java.util.Collection

java.util.Collection List与其子类 Set与其子类

java.util (Collection接口和Map接口)

如何正确实现java.util.Collection类?

搜索适配器 - 空对象引用上的“java.lang.Object[] java.util.Collection.toArray()”