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.
The advantage of
mapMulti()
is that it consumes new elements which became a part of the stream, replacing the initial element (opposed toflatMap()
which internally generates a new stream for each element). If you're generating a fully-fledged stream with a terminal operation inside themapMulti()
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: