ConceptDifficulty: Intermediate1 min

Stream Laziness: Intermediate and Terminal Operations

Four lines that filter, transform and print a list, and print nothing at all.

A stream is a pipeline over a source of elements. Its intermediate operations, such as filter and map, only describe work and return another stream; its terminal operation, such as toList or forEach, runs the whole pipeline. Without a terminal operation, nothing happens.

These four lines filter, transform and print a list. They run without error, print nothing, and take no measurable time:

java
invoices.stream()
        .filter(i -> i.pence() > 10_000)
        .map(Invoice::reference)
        .peek(System.out::println);

Nothing ran. filter and map do no work: each records that the work should happen and returns a new stream. peek, which looks at each element as it passes, is intermediate as well. The pipeline is a description, and a description executes nothing.

The table sorts every stream operation into one of the two kinds:

The two kinds of stream operation
KindReturnsRuns the pipelineExamples
IntermediateAnother streamNofilter, map, sorted, limit, distinct
TerminalA value, or nothingYescollect, forEach, count, findFirst, reduce

There is no terminal operation in the listing, so the description was built and discarded. Replacing peek with forEach makes it print, because forEach is terminal and terminal operations are what make anything happen.

So the shape of every pipeline is the same: a source, some description, and exactly one thing at the end that asks for a result. If nothing happened, look at the last line first.