Java-Stream - mapMulti() with Infinite Streams

408 views Asked by At

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.

Note: 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.

1

There are 1 answers

8
Alexander Ivanchenko On BEST ANSWER

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 fully-fledged stream with a terminal operation inside the mapMulti() it should be executed. And you've created an infinite stream which can't terminate (as @Lino has pointed out in the comment).

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.