Java Stream API — Intermediate and Terminal Operations Deep Dive
Fast recall
Quick revision
Core answer
filter, map, flatMap, distinct, sorted, limit, skip, peek — transform the stream and return another stream. They are lazy — nothing actually executes until a terminal operation is attached. Terminal operations — forEach, collect, reduce, count, findFirst, anyMatch, toArray — produce a result or side effect and trigger execution of the pipeline. A stream can be consumed only once: after the terminal operation runs, calling another operation throws IllegalStateException. The three-part mental model: source → zero or more intermediates → one terminal — every stream pipeline has this shape.Whether you know the stream pipeline mental model — source, intermediates (lazy), terminal (eager) — and can list the most common operations in each category
Calling a stream a 'collection'; assuming intermediate operations execute immediately; reusing a consumed stream (throws IllegalStateException)
Explain lazy evaluation and short-circuiting working together (e.g. `findFirst` stops the pipeline mid-traversal), and mention stateful vs stateless intermediates (`sorted` is stateful, `map` is stateless)
Interview-ready guide
Interview answer
A Stream is a pipeline, not a data structure. It pulls elements from a source — a List, array, generator, or I/O channel — and pushes them through a chain of operations.
Every stream pipeline has exactly three parts: source, zero or more intermediate operations, and exactly one terminal operation.
Intermediate operations — filter, map, flatMap, distinct, sorted, limit, skip, peek — return another stream so you can chain. Critically, they're lazy — nothing actually executes until a terminal operation is attached.
Terminal operations — forEach, collect, reduce, count, findFirst, anyMatch, toArray — produce a result and trigger pipeline execution. After the terminal runs, the stream is consumed and can't be reused.
The interview differentiator is explaining how laziness and short-circuiting combine. stream.filter(...).findFirst() on a 10-million-element source may examine only a handful of elements — findFirst short-circuits and upstream filters run only as far as needed. Without laziness, every element would be filtered before findFirst got a chance.
Another detail: stateless vs stateful intermediates. map and filter are stateless — one element at a time, parallelize trivially. sorted and distinct are stateful — must buffer or coordinate. The practical consequence: put filters before sorts so you sort less data.
Final thing: a stream is one-shot. If you need multiple traversals, either collect to a List first, or wrap in a Supplier. Storing a Stream in a field is almost always a bug.
Java Stream API — Intermediate and Terminal Operations Deep Dive
Direct Answer
A Stream is a sequence of elements from a source (collection, array, I/O channel, generator) that supports a pipeline of operations. Operations fall into two categories. Intermediate operations — filter, map, flatMap, distinct, sorted, limit, skip, peek — transform the stream and return another stream. They are lazy — nothing actually executes until a terminal operation is attached. Terminal operations — forEach, collect, reduce, count, findFirst, anyMatch, toArray — produce a result or side effect and trigger execution of the pipeline. A stream can be consumed only once: after the terminal operation runs, calling another operation throws IllegalStateException. The three-part mental model: source → zero or more intermediates → one terminal — every stream pipeline has this shape.
Common Mistakes & Pitfalls
Calling a stream a 'collection'; assuming intermediate operations execute immediately; reusing a consumed stream (throws IllegalStateException)
Check your understanding
Answer these without looking back at the article.
- What happens if you call a terminal operation twice on the same stream?
- How does `limit(n)` behave differently on ordered vs unordered parallel streams?
- Why is `peek` often misused, and what is its legitimate purpose?
- When would you use `Stream.iterate` or `Stream.generate` instead of collecting to a list first?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.