Java 8 - 流意识形态

Bob*_*r02 14 java collections lambda java-8

我最近开始玩Java 8,之前已经在Haskell/Scala中做过点点滴滴.我正在尝试使用Java中的高阶函数,例如map或者forEach,我正在努力理解将一切都推向Stream意识形态的动机是什么.我理解它提供了很好的通用抽象,它应该是懒惰的,但让我们考虑一个非常简单的常见例子:

list.map(x -> do_sth(x));
Run Code Online (Sandbox Code Playgroud)

很常见的习语,期待这个回归List<T>.现在,在Java 8中,我需要做这样的事情:

list.stream().map(x -> doSth(x)).collect(Collectors.toList())
Run Code Online (Sandbox Code Playgroud)

现在,到目前为止,我看到这个,在调用collect之前,流将不会应用地图,因此将会有一个通过集合下的集合.我也看不出是为什么地图,列表如常见的使用情况map.toList(),list.groupBy()将不会被添加到相应的接口?我在这里缺少一个潜在的设计决策吗?

Stu*_*rks 24

已经将一些新方法直接添加到各种集合中,这些集合急切地对这些集合执行变异操作.例如,要在列表的每个元素上运行函数,用返回值替换原始元素,请使用List.replaceAll(UnaryOperator).这样其他例子是Collection.removeIf(Predicate),List.sort()Map.replaceAll(BiFunction).

相比之下,Stream中添加了许多新方法,例如filter,map,skip,limit,sorted,distinct等.其中大多数都是惰性的,它们不会改变源代码,而是将元素传递给下游.我们确实考虑过将这些直接添加到集合类中.此时出现了几个问题.我们如何将急切的,变异的操作与懒惰的流产生操作区分开来?重载很困难,因为它们有不同的返回类型,所以它们必须有不同的名称.这些行动将如何被束缚?急切的操作必须生成集合来存储中间结果,这可能非常昂贵.由此产生的集合API会产生令人困惑的混合,包括渴望,变异和懒惰的非变异方法.

二阶考虑因素是与添加默认方法的潜在不兼容性.向接口添加默认方法的最大风险是与该接口的实现上的现有方法的名称冲突.如果具有相同名称和参数(通常没有参数)的方法具有不同的返回类型,则这是不可避免的不兼容性.出于这个原因,我们一直不愿意添加大量的默认方法.

出于这些原因,我们决定将惰性,非变异方法保留在流API中,代价是需要额外的方法调用stream()和collect()来在集合和流之间进行桥接.对于一些常见情况,我们将急切的,变异的调用直接添加到集合接口,例如我上面列出的那些.

有关进一步的讨论,请参阅lambdafaq.org.

  • 如果你有`toList`,你可能也想要'toSet`和`toMap`.但是你仍然需要`collect`方法,因为它非常灵活.所以现在一些收集操作会有自己专用的便利方法,而对于其他收集操作,你需要调用`collect`.也许方便是值得的不整洁和不一致,但设计师不这么认为. (5认同)