Java 8流短路

时间:2015-08-24 22:37:03

标签: java java-8 java-stream short-circuiting

在Java 8上读了一下,我得到this博客文章解释了一些关于流和减少它们的内容,以及什么时候可以缩短缩减。在底部说明:

  

注意在findFirstfindAny的情况下,我们只需要与谓词匹配的第一个值(尽管findAny不能保证返回第一个值)。但是,如果流没有排序,那么我们希望findFirst的行为类似于findAny。操作allMatchnoneMatchanyMatch可能根本不会使流短路,因为它可能会评估所有值以确定运算符是true还是{{ 1}}。因此,使用这些的无限流可能不会终止。

我得到falsefindFirst可能会缩短缩减,因为一旦找到元素,您就不需要再进行处理了。

但是为什么findAnyallMatchnoneMatch无法做到这一点?对于anyMatch,如果找到与谓词不匹配的值,则可以停止处理。同样没有。并且allMatch对我来说特别没有意义,因为它几乎等于anyMatch(除了返回的内容)?

说这三个可能不会短路,因为可能需要评估所有值,也可以说findAny

我缺少一些根本区别吗?我真的不明白发生了什么事吗?

4 个答案:

答案 0 :(得分:19)

有一个微妙的区别,因为anyMatch系列使用谓词,而findAny系列则没有。从技术上讲,findAny()看似anyMatch(x -> true)anyMatch(pred)看起来像filter(pred).findAny()。所以这里有另一个问题。考虑一下我们有一个简单的无限流:

Stream<Integer> s = Stream.generate(() -> 1);

所以确实将findAny()应用于此类流将始终短路并完成,而应用anyMatch(pred)取决于谓词。但是,让我们过滤我们的无限流:

Stream<Integer> s = Stream.generate(() -> 1).filter(x -> x < 0);

结果流是否也是无限的?这是一个棘手的问题。它实际上不包含任何元素,但为了确定这一点(例如,使用.iterator().hasNext()),我们必须检查无限数量的底层流元素,因此此操作永远不会完成。我也称这种流为无限。但是,使用此类流anyMatchfindAny永远不会完成:

Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true);
Stream.generate(() -> 1).filter(x -> x < 0).findAny();

所以findAny()也不能保证完成,这取决于之前的中间流操作。

总而言之,我认为该博客文章具有误导性。在我看来,无限流行为在官方JavaDoc中有更好的解释。

答案 1 :(得分:6)

回答已更新

我说博客文章说“findFirst或findAny我们只需要与谓词匹配的第一个值”时就错了。

allMatch(Predicate)anyMatch(Predicate)noneMatch(Predicate)findAny()findFirst()的javadoc中:

  

这是一种短路终端操作。

但请注意,findFirstfindAny没有Predicate。因此,他们可以在看到第一个/任何值后立即返回。其他3个是有条件的,如果条件永远不会触发,它可能永远循环。

答案 2 :(得分:3)

根据Oracle的流文档:  https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps

  

如果在提供无限输入时,终端操作可以在有限时间内终止,则该终端操作是短路的。在流水线中进行短路操作是处理无限流以在有限时间内正常终止的必要但不充分的条件。

所有五个功能都有一行:

  

这是一种短路终端操作。

在功能描述中。

答案 3 :(得分:0)

anyMatch,noneMatch和allMatch返回布尔值,因此他们可能必须检查所有以证明逻辑。

findFirst和findAny只关心找到他们能做的第一个并返回它。

编辑: 对于给定的数据集,Match方法保证始终返回相同的值,但Find方法不是因为顺序可能会有所不同并影响返回的值。

所描述的短路问题是关于给定数据集缺乏一致性的Find方法。