Java 8流短路

Java 8 stream short-circuit

阅读了一些关于 Java 8 的内容,我进入了 this 博客 post 解释了一些关于流和它们的减少,以及何时可以缩短 -电路的减少。底部写着:

Note in the case of findFirst or findAny we only need the first value which matches the predicate (although findAny is not guaranteed to return the first). However if the stream has no ordering then we’d expect findFirst to behave like findAny. The operations allMatch, noneMatch and anyMatch may not short-circuit the stream at all since it may take evaluating all the values to determine whether the operator is true or false. Thus an infinite stream using these may not terminate.

我知道 findFirstfindAny 可能会使还原短路,因为一旦找到元素,就不需要进一步处理。

但是,为什么 allMatchnoneMatchanyMatch 无法做到这一点?对于allMatch,如果发现与谓词不匹配,则可以停止处理。 none 也一样。 anyMatch 对我来说尤其没有意义,因为它几乎等于 findAny (除了返回的内容)?

说这三个可能不会短路,因为可能需要评估所有的值,也可以说是findFirst/Any

我是否遗漏了一些根本的区别?我是不是不太明白这是怎么回事?

当 javadoc 说 "may not short-circuit" 时,它只是指出它不是短路操作,并且根据值,可能会处理整个流。

另一方面,

findFirstfindAny 保证短路,因为它们一旦满足就永远不需要处理流的其余部分。

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

findFirst 和 findAny 只关心找到他们能找到的第一个,然后 returning 那个。

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

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

答案已更新

我会说博客 post 说 "findFirst or findAny we only need the first value which matches the predicate" 是错误的。

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

This is a short-circuiting terminal operation.

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

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

A terminal operation is short-circuiting if, when presented with infinite input, it may terminate in finite time. Having a short-circuiting operation in the pipeline is a necessary, but not sufficient, condition for the processing of an infinite stream to terminate normally in finite time.

所有五个函数都有一行:

This is a short-circuiting terminal operation.

在函数的描述中。

有细微差别,因为 anyMatch family 使用谓词,而 findAny family 不使用谓词。从技术上讲,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()也不一定能完成,要看之前的中间流操作

总而言之,我认为该博客-post 极具误导性。在我看来,无限流行为在官方 JavaDoc.

中得到了更好的解释
LongStream.range(0, Long.MAX_VALUE).allMatch(x -> x >= 0)

LongStream.range(0, Long.MAX_VALUE).allMatch(x -> x > 0)

第一个returns永远,第二个returns立即