Java 16 introduces a new Stream.mapMulti
method which allows you to replace elements in a stream with multiple elements.
The example below shows how you can use mapMulti
to replace each string in a stream with its uppercased and lowercased versions:
Stream.of("Twix", "Snickers", "Mars") .mapMulti((s, c) -> { c.accept(s.toUpperCase()); c.accept(s.toLowerCase()); }) .forEach(System.out::println); Output: TWIX twix SNICKERS snickers MARS mars
The same thing can also be achieved using flatMap
like this:
Stream.of("Twix", "Snickers", "Mars") .flatMap(s -> Stream.of(s.toUpperCase(), s.toLowerCase())) .forEach(System.out::println);
So what is the difference between mapMulti
and flatMap
? According to the javadocs:
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.
- When it is easier to use an imperative approach for generating result elements than it is to return them in the form of a Stream.
Inspecting the code for multiMap
, we can see that it delegates to flatMap
, however, it makes use of a SpinedBuffer
to hold the elements before creating the stream, thus avoiding the overhead of creating new streams per group of result elements.
default <R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper) { Objects.requireNonNull(mapper); return flatMap(e -> { SpinedBuffer<R> buffer = new SpinedBuffer<>(); mapper.accept(e, buffer); return StreamSupport.stream(buffer.spliterator(), false); }); }