Array Type StreamsS2C Home « Array Type Streams

We are not only limited to creating streams from collections using the stream() method of the Collection<E> interface as we have done in previous lessons. What if we want to create streams from arrays? Well we can and in this lesson we learn various ways of doing just that.

There are a couple of options when creating streams from arrays, using the of() static method of the Stream<E> interface and using the overloaded stream() static methods of the Arrays class.

We will start by looking at the of() method.

Using Stream.of() Top

Following is a TestArrayStreamsA class to demonstrate stream creation from arrays using the of() Static method of the Stream<E> interface.


package com.server2client;

import java.util.stream.Stream;

/* Create streams from arrays */
public class TestArrayStreamsA {

    public static void main(String[] args) {

        // Create an array and stream it
        String[] strArray = {"one", "two", "three", "four"};
        Stream<String> strArrayStream = Stream.of(strArray);
        strArrayStream.forEach(System.out::print);

        Stream<String> strArrayStream2 = Stream.of(strArray);
        strArrayStream2.map(String::toUpperCase)
                .forEach(System.out::print);

        // Create an empty stream
        Stream<String> wordStream = Stream.empty();

        // Split into array and create stream
        String sentence = "The quick brown fox jumps over the lazy dog";
        wordStream = Stream.of(sentence.split("\\PL+"));
        wordStream.forEach(System.out::print);

        long count = wordStream.filter(e -> e.contains("o"))
                .count();
        System.out.println("Words containing the letter o: " + count);

        // Create stream from individual entries
        Stream<String> indWordsStream = Stream.of("A", "stitch", "in", "time", "saves", "nine");
        indWordsStream.forEach(System.out::print);
    }
}

Building and running the TestArrayStreamsA class produces the following output:

Run TestArrayStreamsA class
Screenshot 1. Running the TestArrayStreamsA class.

Something went wrong! The error is telling us we are trying to reuse a stream that has already been operated upon. Looking at the code we are using the wordStream stream twice; as mentioned in the Streams & Collections Differences section, streams are consumed after use and cannot be reused.

Removing or commenting out the line wordStream.forEach(System.out::print); will correct the error.

Rebuilding and running the TestArrayStreamsA class produces the following output:

Run TestArrayStreamsA class again
Screenshot 2. Rebuilding and running the TestArrayStreamsA class.

The TestArrayStreamsA class runs fine now as shown in the screenshot. We created streams from arrays using the of() static method of the Stream<E> interface.

We used the map() intermediate operator, for the first time, which returns a stream consisting of the results of applying the given function to the elements of this stream. In our example this was changing all letters to upper case.

Using Arrays Class Top

There are several overloaded static stream() methods in the Arrays class that we can use to convert arrays to streams, mostly dealing with numeric primitives which will be discussed in detail in the next lesson Numeric Streams, the rest we look at here:


package com.server2client;

import java.util.Arrays;
import java.util.stream.Stream;

/* Create streams from arrays */
public class TestArrayStreamsB {

    public static void main(String[] args) {

        // Create an array and stream it
        String[] strArray = {"one", "two", "three", "four"};
        Stream<String> strArrayStream = Arrays.stream(strArray);
        strArrayStream.forEach(System.out::print);

        Stream<String> strArrayStream2 = Arrays.stream(strArray);
        strArrayStream2.map(String::toUpperCase)
                .forEach(System.out::print);

        // Split into array and create stream
        String sentence = "The quick brown fox jumps over the lazy dog";
        Stream<String> wordStream = Arrays.stream(sentence.split("\\PL+"));

        long count = wordStream.filter(e -> e.contains("o"))
                .count();
        System.out.println("Words containing the letter o: " + count);

        // Create stream from individual entries
        Stream<String> indWordsStream = Arrays.stream(new String[]{"A", "stitch", "in", "time", "saves", "nine"});
        indWordsStream.forEach(System.out::print);

        // Create stream from parts of an array
        Stream<String> indWordsStream2 = Arrays.stream(new String[]{"A", "stitch", "in", "time", "saves", "nine"}, 1, 4);
        indWordsStream2.forEach(System.out::print);
    }
}

Running the TestArrayStreamsB class produces the following output:

Run TestArrayStreamsB class
Screenshot 3. Running the TestArrayStreamsB class.

We created streams from arrays using the stream() static method of the Arrays class and the overloaded version that takes start (inclusive) and end (exclusive) positions within the array .

Stream.of() OR Arrays.stream() ? Top

So which should we use Stream.of() or Arrays.stream()? On the surface they seem to do much the same thing but there are subtle differences dependant upon the type used. With our examples so far we have been creating streams of objects, in our case String objects and in these cases both methods return a stream of objects Stream<T>. But what if we wanted to stream a primitive type array, how would this work?

Lets code this up and find out using a simple int primitive array!


package com.server2client;

import java.util.Arrays;
import java.util.stream.Stream;

/* Create streams from arrays */
public class TestArrayStreamsC {

    public static void main(String[] args) {

        // Creating a primitive int array
        int[] intArray = { 1, 2, 3, 4, 5 };

        // Arrays.stream()
        Stream<int[]> stream = Arrays.stream(intArray);
        // Displaying elements in Stream
        stream.forEach(System.out::println);

        // Stream.of
        Stream<int[]> stream2 = Stream.of(intArray);
        // Displaying elements in Stream2
        stream2.forEach(System.out::println);
    }
}

Building the TestArrayStreamsC class produces the following output:

Run TestArrayStreamsC class
Screenshot 4. Building the TestArrayStreamsC class (first attempt).

Something went wrong! The compiler is telling us about incompatible types and is expecting an IntStream.

Looking through the java documentation for the Arrays class it seems we have inadvertently used another overloaded stream() method that accepts an int[] array, that being stream(int[]). This method expects to return an IntStream object like the compiler is telling us. There are also overloaded stream() methods that accept a double[] array and return a DoubleStream and long[] array and return a LongStream

Lets change the line:
Stream<int[]> stream = Arrays.stream(intArray);
to accept an IntStream object as follows:
IntStream stream = Arrays.stream(intArray);

Rebuilding and running the TestArrayStreamsC class produces the following output:

Run TestArrayStreamsC class again
Screenshot 5. Rebuilding and running the TestArrayStreamsC class (second attempt).

The TestArrayStreamsC class runs fine now as shown in the screenshot. There is still a problem though as we are just seeing an object reference for the Stream.of() output.

For object type arrays the overloaded Stream.of static method that takes varargs is called. This calls the Arrays.stream() method under the bonnet, as shown below, so the return types are the same.

Stream.of overloaded method 1
Screenshot 6. Stream.of overloaded method for object type arrays.

However, for primitive type arrays the overloaded Stream.of method that takes an object is called (arrays are objects) and this returns a stream containing a single object, in our case Stream<int[]>.

Stream.of overloaded method 2
Screenshot 7. Stream.of overloaded method for primitive type arrays.

To extract the values and print out the contents we will have to flatten the stream using the flatMapToInt() intermediate operation of the Stream<T> interface, which returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream, produced by applying the provided mapping function to each element.

There are also flatMapToDouble() and flatMapToLong() versions of this method.

Following is the revised code.


package com.server2client;

import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/* Create streams from arrays */
public class TestArrayStreamsC {

    public static void main(String[] args) {

        // Creating a primitive int array
        int[] intArray = { 1, 2, 3, 4, 5 };

        // Arrays.stream()
        IntStream stream = Arrays.stream(intArray);
        // Displaying elements in Stream
        stream.forEach(System.out::println);

        // Stream.of
        Stream<int[]> stream2 = Stream.of(intArray);
        
        // Flatten Stream<int[]> into IntStream
        IntStream stream3 = stream2.flatMapToInt(Arrays::stream);
        // Displaying elements in Stream2
        stream3.forEach(System.out::println);
    }
}

Rebuilding the TestArrayStreamsB class produces the following output:

Run TestArrayStreamsC class 3
Screenshot 8. Rebuilding the TestArrayStreamsC class (third attempt).

OK this all works fine now. So what have we learnt?

If your streaming arrays of objects then the Stream.of static method and the Arrays.stream() method both end up using Arrays.stream().

If you're streaming primitives use the Arrays.stream() variants that were built for this purpose.

If you want to stream boolean, byte, char and short primitives use an IntStream.

If you want to stream float primitives use a DoubleStream.

Related Quiz

Streams Quiz 4 - Array Type Streams Quiz

Lesson 4 Complete

In this lesson we looked at various ways in which we can create streams from arrays.

What's Next?

In the next lesson we look at numeric streams.