Parallel Streams
A collection serves as the source of values for a stream, and this applies to lists, sets, and any other collection.
Why the Creation Call Matters
A stream is a way of processing a sequence of values, but a stream never appears 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 you think about how a stream is processed, you need to be precise about how the stream is born from the collection, because the call you use to create it decides what kind of stream you get.
What do you think happens?
Given a list named c, which kind of stream does c.stream() produce?
Reveal answer
A sequential stream
Calling c.stream() on a collection produces a sequential stream holding the same values as the collection. The name stream() asks for a sequential stream, while parallelStream() asks for a parallel one.
Tracing Values From a Collection Into a Stream
Think of the collection as the source and the stream as the channel that carries its values. The collection holds the values; the stream is created from it and delivers those same values for processing. The same source can feed either kind of stream. What changes between one creation call and another is not the collection, which stays the same, but the kind of stream that comes out of it.
This works the same way for lists and sets. You do not need a different technique for each type of collection. If you know the creation call, you already know which kind of stream the collection will feed.
Two Direct Ways to Create a Stream
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. Both calls start from the same collection and draw the same values. The difference lies only in the kind of stream each call builds.
4
4- numbers is the collection that supplies the values
stream()asks for a sequential stream from numbersparallelStream()asks for a parallel stream from the same numbers- The filter and count steps are identical in both pipelines; only the creation call differs
In the example, the two pipelines differ only in the first call after numbers. Both count the even values in the list, which are 4, 8, 16, and 42, so both print 4. Reading the names tells you the kind of stream: stream() gives a sequential stream and parallelStream() gives a parallel one.
Deriving a Parallel Stream With parallel()
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(), with one extra step. Both forms are valid. You will see the stream() plus parallel() form in code that wants the sequential start visible in the source.
4stream()creates a sequential stream from numbersparallel()changes that stream into a parallel stream- The filter and count operations are unchanged by the switch
The diagram traces the derived route. The list supplies the values, stream() creates a sequential stream from it, and parallel() changes that stream's mode. The source collection is unchanged by the extra call, and the values draw from the same collection. Only the mode of the stream changes, which is why the result is a parallel stream.
How a Parallel Stream Handles Its Values
A parallel stream is designed to process its values in parallel rather than one step after another. The diagram below gives a high-level picture of this. The source pack for this article does not describe the internal splitting or recombination in detail, so treat the figure as an overview of the idea rather than a precise account of how the work is divided.
Mistakes Beginners Make With Creation Calls
Common mistake Assuming stream() creates a parallel stream because the collection is large
What it looks likeList<Integer> big = ...; big.stream() is treated as parallelWhy it failsThe method name determines the kind of stream.
stream()always asks for a sequential stream.Do this insteadUse parallelStream() or add parallel() if you want a parallel stream.
Common mistake Thinking parallelStream() and stream() draw different values
Why it failsBoth start from the same collection and draw the same values. Only the kind of stream differs.
Do this insteadCompare the creation calls by name, not by the data they hold.
Common mistake Believing parallel() changes the collection itself
Why it failsparallel()is called on a stream and changes the stream's mode. The collection that supplied the values is not altered by this call.Do this insteadTrack the stream, not the collection, when you read a chain that includes parallel().
Common mistake Forgetting that parallelStream() and stream().parallel() reach the same kind of stream
Comparing the Three Creation Forms
| Creation call | Starting point | Kind of stream produced | Route |
|---|---|---|---|
| c.stream() | Collection c | Sequential | One direct call |
| c.parallelStream() | Collection c | Parallel | One direct call |
| c.stream().parallel() | Collection c, then a sequential stream | Parallel | Two steps |
The three creation forms for a stream built from a collection named c
Predicting the Stream Type
Given a list named names, predict which kind of stream each of these calls produces: names.stream(), names.parallelStream(), and names.stream().parallel(). Then state which call takes a sequential start and adds one step to become parallel.
Hints
- The method name tells you which kind of stream you are asking for
stream()on its own gives a sequential streamparallel()is called on a stream, after the stream has been created
Key Takeaways
- A collection is the source of values for a stream, and the same idea applies to lists, sets, and other collections.
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 produces a parallel stream from a sequential start.- The method name determines the kind of stream, so reading the creation call tells you how it will be processed.