Turn a Stream of Arrays to Single Stream in Java



This site utilizes Google Analytics, Google AdSense, as well as participates in affiliate partnerships with various companies including Amazon. Please view the privacy policy for more details.

Recently I was working with an array of objects where each object itself held an array of different objects. I wanted to go through each of the second items via a Java 8 Stream.

Essentially I had a class that looked something like the following:

public class ArrayHolder {
   public Object[] getArray() {
      return new Object[5];
   }
}

Of course, I had an array of instances of that class:

final ArrayHolder[] holders = {new ArrayHolder(), new ArrayHolder(), new ArrayHolder(), new ArrayHolder()};

I wanted to go through all the items in the second array. Prior to Java 8 and streams, I’d do it with two nested for loops:

for (ArrayHolder holder : holders) {
    for (Object object : holder.getArray()) {
        // do the thing
    }
}

But now, with Java 8, I wanted to do it with streams.

Going through an array via streams is easy enough:

Arrays.stream(holders)

And I can map that stream to the getArray method:

Arrays.stream(holders)
      .map(ArrayHolder::getArray)

But when I go to do something, say, with the forEach method, it wants to do things to the array, not the individual objects:

Arrays.stream(holders)
      .map(ArrayHolder::getArray)
      .forEach(thisIsAnArray -> thisIsAnArray.length);

Initially, I tried to call flatMap, but that didn’t work:

Arrays.stream(holders)
      .flatMap(ArrayHolder::getArray)

This just gives me the following compiler errors:

The method flatMap(Function<? super ArrayHolder,? extends Stream<? extends R>>)
in the type Stream<ArrayHolder> is not applicable for the arguments (ArrayHolder::getArray)

The type of getArray() from the type Main is Object[],
this is incompatible with the descriptor's return type: Stream<? extends R>

It does turn out that flatMap is what I wanted, I just needed to call it after the initial map call. flatMap takes a Stream, so I need to convert the array to a stream… Which I already know how to do, being that’s what I started with:

Arrays.stream(holders)
      .map(ArrayHolder::getArray)
      .flatMap(Arrays::stream);

Now I can totally do things on the individual objects:

Arrays.stream(holders)
      .map(ArrayHolder::getArray)
      .flatMap(Arrays::stream)
      .forEach(thisIsAnObject -> thisIsAnObject.toString());

Fun fact: this works on 2D arrays as well:

Arrays.stream(new Object[2][2])
      .flatMap(Arrays::stream);

Here’s a GitHub Gist I created that demonstrates how to turn the stream of arrays into a single string:

Happy coding!

Leave a Reply

Note that comments won't appear until approved.