Sequential Streams
A collection serves as the source of values for a stream, and this applies to lists, sets, and any other collection.
Why a Stream Needs a Starting Point
What do you think happens?
Given a list named names, what kind of stream does names.stream() produce?
Reveal answer
A sequential stream
Calling stream() on a collection creates a sequential stream that holds the same values as the collection. The method name tells you which kind of stream you get.
A stream is a way of processing a sequence of values, but it does not appear out of nowhere. Every stream needs a starting point that supplies the values it will work on. In this article, that starting point is a collection such as a list or a set. Before looking at how a stream is processed, it helps to be precise about how the stream is born from the collection.
The question this article answers is simple to state: when you write a creation call on a collection, how do you know which kind of stream you will get? The answer depends on the method name, and the rest of the article shows how to read it.
Tracing Where Stream Values Come From
A collection serves as the source of values for a stream. This applies to lists, sets, and any other collection. The stream does not need its own storage of values before processing begins; it draws its values from the collection it was created from.
Follow the path of the data in the diagram below. The values flow out of the collection c and into whichever stream the creation call builds. Notice that the collection is the origin in every case, and the creation call decides what kind of stream receives those values.
The diagram makes one point clear. Both calls start from the same collection and draw the same values. The difference lies in the kind of stream each call builds, not in the values it can reach.
A sequential stream is the stream produced by calling stream() on a collection. It holds the same values as the collection. A parallel stream is the stream produced by calling parallelStream() on a collection, or by calling parallel() on an existing sequential stream.
Naming the Two Creation Calls
Given a collection named c, there are two direct ways to obtain a stream from it. Calling c.stream() produces a sequential stream that holds the same values as the collection. Calling c.parallelStream() produces a parallel stream from the same collection.
The method name is the deciding signal. stream() asks for a sequential stream, and parallelStream() asks for a parallel stream. Keeping these two names straight is the core skill of this article, because the name is the only thing that changes between the two calls.
stream()on the collection creates a sequential streamparallelStream()on the same collection creates a parallel stream- Both lines use the same source collection, names
Predicting the Kind of Stream From a Creation Call
A program has a set named tags. Predict which kind of stream is produced by tags.parallelStream(), and say what the stream holds.
- 1Identify the source
The call is made on tags, which is a set. A set is a collection, so it can serve as the source of values for a stream.
- 2Read the method name
The method is
parallelStream(). The method name determines the kind of stream, andparallelStream()creates a parallel stream. - 3Check what the stream holds
The stream is created from the same collection and holds the same values as tags. Only the kind of stream differs from a
stream()call.
tags.parallelStream() produces a parallel stream that holds the same values as the set tags.
Reaching a Parallel Stream in Two Steps
There is a second route to a parallel stream. You can first create a sequential stream with stream() and then call parallel() on it. The result is a parallel stream, so this route reaches the same destination as parallelStream(), just with one extra step.
Both forms are valid. The two-step form is useful in code that wants the sequential start visible in the source, because the stream() call shows that the stream began as sequential before parallel() changed it.
- The first line reaches a parallel stream in one call
- The second line starts sequential with
stream(), then callsparallel() - Both lines produce a parallel stream from the same collection
| Creation form | Steps | Kind of stream produced |
|---|---|---|
| c.stream() | One call on the collection | Sequential |
| c.parallelStream() | One call on the collection | Parallel |
| c.stream().parallel() | Two calls: sequential start, then parallel() | Parallel |
Quick reference for the three creation forms covered in this article
Mistakes When Reading Creation Calls
Common mistake Assuming that every call to stream() on a collection is parallel
What it looks likenames.stream() is written, but the reader expects multiple threads to handle the values.
Why it failsThe method name determines the kind of stream.
stream()creates a sequential stream.Do this insteadRead the method name first. stream() gives a sequential stream, and parallelStream() gives a parallel one.
Common mistake Treating stream() and parallelStream() as differing in which values they contain
What it looks likeBelieving parallelStream() on a set pulls different elements than stream() on the same set.
Why it failsBoth calls start from the same collection and draw the same values. The difference is the kind of stream built.
Do this insteadKeep the values fixed in your head and change only the stream kind when you compare the two calls.
Common mistake Thinking parallel() needs a new collection
What it looks likeCreating a second list before calling parallel() on the stream.
Why it failsparallel()is called on an existing sequential stream, so the collection is not required to change.Do this insteadCall stream() on the collection, then call parallel() on the resulting stream.
Common mistake Assuming a set cannot be a stream source because it is not a list
Predicting Stream Kinds in Practice
A program contains a list named orders. For each of the following expressions, predict whether it produces a sequential stream or a parallel stream: orders.stream(), orders.parallelStream(), and orders.stream().parallel(). Then explain what the three expressions have in common.
Hints
- Look at the method name first. Which name contains parallel?
- The two-step form starts with
stream(), so think about whatparallel()changes. - The values drawn from orders are the same in all three cases.
Key Takeaways
- A collection, such as a list or a set, serves as the source of values for a stream.
c.stream()creates a sequential stream, andc.parallelStream()creates a parallel stream from the same collection.c.stream().parallel() is a two-step route that also yields a parallel stream from a sequential start.- The method name determines the kind of stream, so reading the creation call tells you how the stream will be processed.