Stream - intermediate operations are lazy

|| intermediate operation || Java || java8 || jdk8 || stream || terminal operation

More formally, on the JDK 8 Stream javadocs:

Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

Which also means that if you don’t have a terminal operation, no intermediate operations code will get executed. This may not be obvious at first sight, though:

On this little example, we’re just creating a List of Strings, and then a Stream of Strings from that very same list. Let’s say that we also want to print all the words on our stream before every step of our Stream processing, which in this case involve:

  1. Filtering the Stream to keep only the words which contain the letter “a” as we start processing them.
  2. Making the remaining Strings uppercase.
  3. Counting them.

The step 3 is commented out, please run this main method and check how nothing was printed out. Now, uncomment line 22 and run it again, you’ll see an output like this:

while filtering (intermediate operation)… yo while filtering (intermediate operation)… quiero while filtering (intermediate operation)… ser while filtering (intermediate operation)… llorando while uppercasing (intermediate operation)… llorando peeking before counting (terminal operation)… LLORANDO while filtering (intermediate operation)… el while filtering (intermediate operation)… hortelano while uppercasing (intermediate operation)… hortelano peeking before counting (terminal operation)… HORTELANO

What makes everything being executed is not the peek operation, which is also an intermediate one, but counting the remaining elements in the Stream, which is a terminal operation and triggers every previous intermediate operation. This may be easy to understand conceptually, but it’s also easy to forget about the terminal operation and wonder why that peek operation is not printing out anything in your console.