Consider this code
Object found = collection.stream()
.filter( s -> myPredicate1(s))
.filter( s -> myPredicate2(s))
.findAny()
Will it process entire stream, and call both myPredicate1
and myPredicate2
for all elements of the collection? Or will as many predicates be called as are needed to actually find the value?
Yes it is, as the Stream.findAny()
documentation states:
This is a short-circuiting terminal operation.
It's a common misconception that objects in stream are "pushed" towards consuming operation. It's actually the other way around - the consuming operation pulls each element.
For sequential streams only as many predicates will be called as are needed to find matching value. Parallel streams may execute more predicates, but will also stop execution as soon as an element is found.
public class StreamFilterLazyTest {
static int stI = 0;
static class T {
public T() {
super();
this.i = ++stI;
}
int i;
int getI() {
System.err.println("getI: "+i);
return i;
}
}
public static void main(String[] args) {
T[] arr = {new T(), new T(), new T(), new T(), new T(), new T(), new T(), new T(), new T(), new T()};
Optional<T> found = Arrays.stream(arr).filter(t -> t.getI() == 3).findAny();
System.out.println("Found: "+found.get().getI());
}
}
will print:
getI: 1
getI: 2
getI: 3
Found: 3