Medium java java-21

What is lazy evaluation in streams?

The 30 second answer

Intermediate operations like filter and map do nothing on their own. Work only starts when a terminal operation runs, and then the stream does only as much as it needs. That is why short-circuit operations like findFirst, anyMatch or limit can stop early, even on an infinite stream. It also means a pipeline with no terminal operation never executes, so side effects inside it never happen.

Because intermediate operations are lazy, the stream can stop as soon as the answer is known:

Stream.iterate(1, i -> i + 1)
      .filter(i -> i % 7 == 0)
      .findFirst();          // Optional[7]; only 7 elements are examined

Stream.of("a", "b").peek(System.out::println);  // prints nothing: no terminal op

Short-circuiting operations are findFirst, findAny, anyMatch, allMatch, noneMatch and limit (plus takeWhile since Java 9). Laziness also lets the library fuse operations into a single pass instead of building intermediate collections.

A common trap: putting logic with side effects in peek or map and assuming it runs. Since Java 9, count() may skip executing the pipeline when it can compute the count directly from the source, and the Javadoc warns that side effects may then not run.

Sources: java.util.stream package summary: laziness and short-circuiting, Stream.count Javadoc)

Sources (0)
See inline citations in the answer above.