Stream mapMulti with infinite streams

I thought that all stream pipelines written using flatMap can be converted to use mapMulti. Looks like I was wrong when the flatMap or mapMulti returns/operates on an infinite stream.

This is for educational purpose only

When we map an element to an infinite stream inside a flatMap followed by a limit(), then the stream pipeline is lazy and evaluates as per the required number of elements.

list.stream()
    .flatMap(element -> Stream.generate(() -> 1))
    .limit(3)
    .forEach(System.out::println);

Output:

1
1
1

But when doing the same in a mapMulti, the pipeline is still lazy i.e., it doesn’t consume the infinite stream. But when running this in IDE (Intellij), it hangs and doesn’t terminate (I guess waiting for other elements consumption) and doesn’t come out of the stream pipeline execution.

With a mapMulti,

list.stream()
    .mapMulti((element, consumer) -> {
        Stream.generate(() -> 1)
            .forEach(consumer);
        })
    .limit(3)
    .forEach(System.out::println);
System.out.println("Done"); //Never gets here

Output:

1
1
1

But the last print (Done) doesn’t get executed.

Is this the expected behaviour?
I couldn’t find any warning or points on infinite stream and mapMulti in Javadoc.

>Solution :

The advantage of mapMulti() is that it consumes new elements which became a part of the stream, replacing the initial element (opposed to flatMap() which internally generates a new stream for each element). If you’re generating a stream inside the mapMulti() it should be consumed (i.e. executed). And you’ve created an infinite stream which can’t be fully consumed.

On the contrary, flatMap() expects a function producing a stream, i.e. function only returns it not processes.

Here’s a quote from the API note that emphasizes the difference between the two operations:

API Note:

This method is similar to flatMap in that it applies a one-to-many
transformation to the elements of the stream and flattens the result
elements into a new stream. This method is preferable to flatMap in
the following circumstances:

  • When replacing each stream element with a small (possibly zero) number of elements. Using this method avoids the overhead of creating
    a new Stream instance for every group of result elements, as required
    by flatMap.

Leave a Reply