Reading up a bit on Java 8, I got to this blog post explaining a bit about streams and reduction of them, and when it would be possible to short-circuit the reduction. At the bottom it states:
Note in the case of
findAnywe only need the first value which matches the predicate (although
findAnyis not guaranteed to return the first). However if the stream has no ordering then we’d expect
findFirstto behave like
findAny. The operations
anyMatchmay not short-circuit the stream at all since it may take evaluating all the values to determine whether the operator is
false. Thus an infinite stream using these may not terminate.
I get that
findAny may short-circuit the reduction, because as soon af you find an element, you don’t need to process any further.
But why would this not be possible for
allMatch, if you find one which doesn’t match the predicate, you can stop processing. Same for none. And
anyMatch especially doesn’t make sense to me, as it it pretty much equal to
findAny (except for what is returned)?
Saying that these three may not short-circuit, because it may take evaluating all the values, could also be said for
Is there some fundamental difference I’m missing? Am I not really understanding what is going on?
There’s a subtle difference, because
anyMatch family uses a predicate, while
findAny family does not. Technically
findAny() looks like
anyMatch(x -> true) and
anyMatch(pred) looks like
filter(pred).findAny(). So here we have another issue. Consider we have a simple infinite stream:
Stream<Integer> s = Stream.generate(() -> 1);
So it’s true that applying
findAny() to such stream will always short-circuit and finish while applying
anyMatch(pred) depends on the predicate. However let’s filter our infinite stream:
Stream<Integer> s = Stream.generate(() -> 1).filter(x -> x < 0);
Is the resulting stream infinite as well? That’s a tricky question. It actually contains no elements, but to determine this (for example, using
.iterator().hasNext()) we have to check the infinite number of underlying stream elements, so this operation will never finish. I would call such stream an infinite as well. However using such stream both
findAny will never finish:
Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true); Stream.generate(() -> 1).filter(x -> x < 0).findAny();
findAny() is not guaranteed to finish either, it depends on the previous intermediate stream operations.
To conclude I would rate that blog-post as very misleading. In my opinion infinity stream behavior is better explained in official JavaDoc.