Concepts / Creating Streams

Creating Streams

An array does not have a stream() method, so you cannot create a stream by calling stream() on the array itself.

  • Programming

Why Streams Need a Starting Point

An array holds a fixed group of values, and many programs need to process every value in that group. Java offers streams as a way to work with such a group. 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. This article is about that starting point: how a stream is born from an array or from a collection.

What do you think happens?

You have an int array named A. Which expression creates a stream from it: A.stream() or Arrays.stream(A)? Make your guess before reading on.

  • A.stream()

  • Arrays.stream(A)

Reveal answer
Answer:

Arrays.stream(A)

An array does not have a stream() method, so you cannot create a stream by calling stream() on the array itself. The ability to create a stream from an array belongs to the static method stream in the class Arrays, which comes from the package java.util. Because the method is static, you call it on the class and pass the array in as the argument.

Tracing the Stream-Creation Line

The program below creates one stream from an array and three from a collection. As you read it, keep one question in mind: at which line does a stream first appear, and does the source passed to it match what you expected? Each stream-creation line is the boundary between the world of arrays and collections and the world of streams.

java
Notes on the code
  • Line 6 declares the array A; it is the source for the first stream.
  • Line 7 declares the collection c; it is the source for the other three streams.
  • Line 9 creates a stream from the array by passing A to the static method Arrays.stream.
  • Line 10 creates a sequential stream from the collection with stream().
  • Line 11 creates a parallel stream from the same collection with parallelStream().
  • Line 12 creates a parallel stream by calling parallel() on a sequential stream.
Code walkthrough
Read the program one stream-creation line at a time and compare each result with its source.
  1. 1
    The array A is the only source for the first stream, and it is passed as the argument to Arrays.stream. The result is a stream built from A's elements.
  2. 2
    The collection c is the source for the next three lines. Each call is made on c itself, so the source is the collection rather than an argument.
  3. 3
    The method name in each call decides the kind of stream: stream() gives a sequential stream, parallelStream() gives a parallel stream.
  4. 4
    The last line starts from a sequential stream and calls parallel() on it, so it also ends with a parallel stream, through one extra step.

Arrays Create Streams Through a Static Method

The ability to create a stream from an array is not a method attached to the array. An array does not have a stream() method, so the call A.stream() cannot be used to create a stream. Instead, the stream comes from a static method named stream in the class Arrays, which is part of the package java.util.

Definition

Arrays.stream(A) is the expression that creates a stream from an array. The class name Arrays tells Java where to look for the method, the method name stream tells Java what to do, and the argument A tells Java which array to use. Because the method is static, you call it on the class itself and pass the array in.

Each part of the expression has a job, and changing any one of them changes what the expression means. Keep the array as the argument. The stream you get back is created from that array, so it holds the values the array holds.

Array AArrays.stream(A)static method injava.util.ArraysCollection cc.stream()sequential streamc.parallelStream()parallel streampassed as argumentmethod callmethod call
Which source and which class or method produce a stream? An array is passed as an argument to Arrays.stream, while a collection calls stream or parallelStream on itself.

Creating Streams from Collections

A collection serves as the source of values for a stream, and this applies to lists, sets, and any other collection. You do not need a different technique for each type of collection. What changes from one creation call to another is not the kind of collection but the kind of stream that comes out of it.

Given a collection named c, there are two direct ways to get a stream. The method name tells you which one you are asking for, and the two calls begin from the same collection and draw the same values.

Source is an array?Arrays.stream(A)stream from array valuesstream()sequential streamMethod name?collection sourceparallelStream()parallel streamyesnostreamparallelStream
Given a creation call, follow the decisions to find which kind of stream results. The source type comes first, then the method name.

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, and you will see the two-step form in code that wants the sequential start visible in the source.

Collection cc.stream()sequential streamCollection cc.stream().parallel()parallel streamstream()stream() then parallel()
When parallel() is called on an existing sequential stream, the stream's kind changes from sequential to parallel. The source collection is the same in both cases.
java
Notes on the code
  • twoStep starts from a sequential stream and then changes it with parallel().
  • oneStep reaches a parallel stream directly with parallelStream().

Mistakes When Creating Streams

The mistakes below come up most often when a stream is created from the wrong source or with the wrong name.

  • Common mistake

    Calling stream() directly on an array

    What it looks like
    int[] A = {4, 8, 15};
    var s = A.stream();
    Why it fails

    An array does not have a stream() method, so the array itself cannot create a stream this way.

    Do this instead
    Pass the array to the static method: var s = Arrays.stream(A);
  • Common mistake

    Expecting different values from stream() and parallelStream()

    Why it fails

    Both calls start from the same collection and draw the same values. The difference is the kind of stream built.

    Do this instead

    Compare the method names to decide the kind of stream, and expect the same source values from either call.

  • Common mistake

    Assuming parallel() creates a sequential stream

    Why it fails

    parallel() is the route to a parallel stream, even when it is applied to a sequential stream.

    Do this instead
    Read c.stream().parallel() as ending in a parallel stream.
  • Common mistake

    Forgetting that the method name sets the stream kind

    Why it fails

    The kind of stream is decided by the creation call, so the name you read is the only signal of the kind.

    Do this instead

    Read the creation line and name the kind before reading any later processing code.

Locating the Departing Line

Now apply the trace method to a program that contains an error. Read the stream-creation lines in order and find the first one where the result is not what you expected.

java
Notes on the code
  • Line 1 declares the array A.
  • Line 2 creates a stream from A correctly by passing it to Arrays.stream.
  • Line 3 tries to call stream() on the array itself.
Worked example

Finding the Line Where Stream Creation Departs

In the program above, which line first produces a stream-creation result that differs from what is expected, and why?

  1. 1
    Check the source of each stream

    The array A is the source for both creation lines, so the question is which form is valid for an array.

  2. 2
    Compare line 2 with the expected form

    Arrays.stream(A) is the static method that creates a stream from an array, so line 2 matches what is expected.

  3. 3
    Compare line 3 with the expected form

    A.stream() asks the array to create a stream through its own stream() method, which the array does not have. Line 3 is the first line where the expected stream does not appear.

  4. 4
    Fix the line

    Replace the call with Arrays.stream(A), passing the array as the argument.

Result

Line 3, the call A.stream(), is the departing line. The correction is var second = Arrays.stream(A);

Predicting Creation Calls

EASY

Given a collection named names, which call produces a parallel stream: names.stream() or names.parallelStream()? Explain your choice in terms of the method name.

Hints
  • Look at the method name in each call.
  • The name parallelStream asks for the parallel kind; the name stream asks for the sequential kind.
MEDIUM

A program has an int array named nums and a list named items. Write one stream-creation line for each source: a sequential stream from nums, and a parallel stream derived from a sequential stream of items. Then identify which of your lines would be wrong if you had written nums.stream() instead of the correct form.

Hints
  • An array's stream comes from the static method in the class Arrays, passed the array as its argument.
  • A two-step parallel stream starts with stream() and then calls parallel().

Key Takeaways

  • An array does not have a stream() method, so a stream from an array is created with the static method Arrays.stream(A) from package java.util.
  • A collection such as a list or a set is the source for a stream. Calling c.stream() gives a sequential stream, and c.parallelStream() gives a parallel stream from the same collection.
  • The method name decides the kind of stream, so read the creation call before reasoning about how the stream is processed.
  • c.stream().parallel() is a two-step route that also yields a parallel stream from a sequential start.
  • When a stream-based result is wrong, trace the stream-creation line first and compare it with the source you passed in.