Why does a Java stream do nothing until a terminal operation is called?
Intermediate operations like filter and map only describe the pipeline. Work starts when a terminal operation such as collect, count or forEach is called, and elements then flow through the whole pipeline one at a time.
Explain it simply
Writing a shopping list does not buy anything. The shopping only happens when you actually go to the market. Intermediate operations write the list; the terminal operation is the trip.
Example
import java.util.*;
import java.util.stream.*;
Stream<Integer> s = List.of(1, 2, 3).stream()
.filter(n -> {
System.out.println("check " + n);
return n > 1;
});
System.out.println("before terminal"); // nothing was checked yet
List<Integer> out = s.toList(); // terminal operation starts the work
System.out.println(out);
// prints:
// before terminal
// check 1
// check 2
// check 3
// [2, 3]What to say in the interview
"Intermediate operations such as filter, map, sorted and distinct return a new stream and are lazy. Terminal operations such as collect, forEach, reduce, count and findFirst trigger the traversal. Because of this, the JVM can fuse steps and short-circuit: with findFirst, the pipeline stops after the first match. A stream also cannot be reused after a terminal operation; trying throws IllegalStateException."
Common mistakes
- Putting a side effect like a print or counter in map and expecting it to run without a terminal operation.
- Reusing the same stream variable twice.