r/JavaProgramming • u/ClickOk5811 • 7h ago
Java streams are lazy: this pipeline over four strings prints only two lines
Here’s the console output of a small program:
filter apple
map apple
That’s all. Four strings went in, and only the first one was ever looked at. Here’s the code:
String result = Stream.of("apple", "banana", "cherry", "date")
.filter(s -> { System.out.println("filter " + s); return s.length() > 4; })
.map(s -> { System.out.println("map " + s); return s.toUpperCase(); })
.findFirst()
.orElse("none");
result is "APPLE".
Two things explain the output.
Intermediate operations don’t run on their own. filter and map only describe what should happen. Nothing executes until a terminal operation like findFirst, collect or forEach asks for elements. If you remove .findFirst().orElse("none") and leave the pipeline hanging, it prints nothing at all.
Elements flow through one at a time. Instead of running filter over all four strings, then map over the survivors, each element goes through the whole chain before the next one starts. apple passes the filter, gets mapped, and arrives at findFirst, which has what it needs, so the pipeline stops. banana, cherry and date are never touched.
That’s why peek and print statements inside a pipeline can look confusing: the order of the output isn’t “all the filters, then all the maps”.
One exception worth knowing: stateful operations like sorted() have to see every element before they can emit the first one, so they break the one-at-a-time flow. A pipeline with sorted() in the middle will process everything up to that point before anything continues.
A practical consequence is that side effects inside map or filter are hard to reason about, because whether and when they run depends on what’s downstream. I’d keep those lambdas free of side effects and use peek only for debugging.
If you’ve hit a bug that came down to laziness, I’d be interested in what it looked like. Mine tend to be the “I added a map and nothing happened” kind.