Java 16的Stream#mapMulti()


如今,新的 Java 版本发布得如此之快,以至于小事情常常被忽视,事实证明,Java 16 为 Stream API 带来了一个新的有趣的补充——你可能还没有听说过的mapMulti()方法。

<R> Stream<R> mapMulti(BiConsumer<? super T, ? super Consumer<R>> mapper)

其核心mapMulti()是flatMap() 的替代方案。两者都用于处理具有一对多语义的 Stream 元素。
但是,mapMulti()使您有机会使用提供的 Consumer 实例手动使用元素:
var lists = of(of(1), of(2, 3), List.<Integer>of());

var result = lists.stream()
  .mapMulti((list, consumer) -> list.forEach(consumer))
  .collect(Collectors.toList());

同样用flatMap() 实现:
// import static java.util.List.of;
var lists = of(of(1), of(2, 3), List.<Integer>of());
var result = lists.stream()
  .flatMap(i -> i.stream())
  .collect(Collectors.toList());

对于某些边缘情况(元素数量较少),mapMulti() 可以更方便、更高效, 因此您应该将新方法视为补充补充而不是改变游戏规则。归根结底,它在内部将工作委托给 flatMap()。
性能提升是通过简化最终传递给 flatMap() 的 Stream 实例的构造来实现的。这是通过将结果元素收集到 SpinedBuffer 中,然后将其转换为 Stream 来实现的:
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);
    });
}

源码: GitHub.