从Java 16开始,何时以及如何在flatMap上执行一到0..n映射Stream mapMulti
我浏览了新闻和Java16的源代码,遇到了名为从Java 16开始,何时以及如何在flatMap上执行一到0..n映射Stream mapMulti,java,java-stream,flatmap,java-16,mapmulti,Java,Java Stream,Flatmap,Java 16,Mapmulti,我浏览了新闻和Java16的源代码,遇到了名为mapMulti的新流方法。早期的访问称它类似于flatMap,并且已经被批准使用相同的Java版本 <R> Stream<R> mapMulti(BiConsumer<? super T,? super Consumer<R>> mapper) 流映射多(BiConsumerStream::mapMulti是一种新方法,被归类为中间操作 它需要一个双消费者映射器将要处理的元素作为消费者。后者使
mapMulti
的新流方法。早期的访问称它类似于flatMap
,并且已经被批准使用相同的Java版本
<R> Stream<R> mapMulti(BiConsumer<? super T,? super Consumer<R>> mapper)
流映射多(BiConsumerStream::mapMulti
是一种新方法,被归类为中间操作
它需要一个双消费者映射器
将要处理的元素作为消费者
。后者使该方法乍看起来很奇怪,因为它不同于我们在其他中间方法中使用的方法,例如映射
,过滤器
,或窥视
,其中没有任何一种方法*消费者的变化
API本身在lambda表达式中提供的使用者
的目的是接受后续管道中可用的任意数量的元素。因此,所有元素,无论有多少,都将被传播
使用简单片段的解释
- 一对一些(0..1)映射(类似于
过滤器
)
仅对少数选定的项目使用使用者.accept(R)
可实现类似筛选器的管道。这在根据谓词检查元素并将其映射到不同值的情况下可能会很有用,否则将使用筛选器
和映射
的组合来完成。下面是
Stream.of(“Java”、“Python”、“JavaScript”、“C#”、“Ruby”)
.mapMulti((str,消费者)->{
如果(str.length()>4){
consumer.accept(str.length());//长度大于4
}
})
.forEach(i->System.out.print(i+);
// 6 10
- 一对一映射(类似于
映射
)
使用上一个示例,如果省略了条件,并且每个元素都映射到一个新元素中,并使用使用者
接受,则该方法的有效行为类似于映射
:
Stream.of(“Java”、“Python”、“JavaScript”、“C#”、“Ruby”)
.mapMulti((str,consumer)->consumer.accept(str.length())
.forEach(i->System.out.print(i+);
// 4 6 10 2 4
- 一对多映射(类似于
flatMap
)
这里的事情变得有趣,因为人们可以调用consumer.accept(R)
任意次数。假设我们想要复制表示字符串长度的数字本身,即2
变成2
,2
,4
变成4
,4
,4
,4
,0
变成零
Stream.of(“Java”、“Python”、“JavaScript”、“C#”、“Ruby”、“Ruby”)
.mapMulti((str,消费者)->{
对于(int i=0;iSystem.out.print(i+);
// 4 4 4 4 6 6 6 6 6 6 10 10 10 10 10 10 10 10 10 10 2 2 4 4 4 4
与flatMap的比较
该机制的核心思想是可以多次调用(包括零次)与flatMap
不同,它在内部使用SpinedBuffer
允许将元素推入单个扁平流实例,而无需为每组输出元素创建新的流实例。使用此方法时,状态两个用例优于flatMap
:
- 使用少量(可能为零)元素替换每个流元素时。使用此方法可避免按flatMap的要求为每组结果元素创建新流实例的开销
- 当使用命令式方法生成结果元素比以流的形式返回它们更容易时
就性能而言,在这种情况下,新方法mapMulti
是赢家。请查看此答案底部的基准测试
过滤器映射方案
使用此方法而不是单独使用过滤器
或映射
是没有意义的,因为它太冗长,而且实际上创建了一个中间流。异常可能是替换.filter(..).map(..)
chain一起调用,在检查元素类型及其类型时非常方便
int sum=1,2.0,3.0,4F,5,6L的流量
.MapMultiPoint((数字,消费者)->{
if(整数的数字实例){
consumer.accept((整数)编号);
}
})
.sum();
// 6
int sum=1,2.0,3.0,4F,5,6L的流量
.filter(数字->整数的数字实例)
.mapToInt(数字->(整数)数字)
.sum();
如上所述,引入了其变体,如和。这来自于原始流中的mapMulti
方法,如。此外,引入了三个新的功能接口。基本上,它们是BiConsumer
的原始变体,例如:
@FunctionalInterface
interface IntMapMultiConsumer {
void accept(int value, IntConsumer ic);
}
组合真实用例场景
这种方法的真正威力在于其使用的灵活性,并且一次只创建一个流,这是比flatMap
的主要优势。下面的两个片段表示产品
及其列表
到0..n
提供的平面映射,由提供
类表示,并基于证书在条件中(产品类别和变化可用性)
产品
带有字符串名称
、国际基价
、字符串类别
和列表变体
变体
带有字符串
Benchmark Mode Cnt Score Error Units
MapMulti_FlatMap.flatMap avgt 25 73.852 ± 3.433 ns/op
MapMulti_FlatMap.mapMulti avgt 25 17.495 ± 0.476 ns/op
Benchmark Mode Cnt Score Error Units
MapMulti_FilterMap.filterMap avgt 25 7.973 ± 0.378 ns/op
MapMulti_FilterMap.mapMulti avgt 25 7.765 ± 0.633 ns/op
Benchmark Mode Cnt Score Error Units
MapMulti_FlatMap_Optional.flatMap avgt 25 20.186 ± 1.305 ns/op
MapMulti_FlatMap_Optional.mapMulti avgt 25 10.498 ± 0.403 ns/op
List<A> list = IntStream.range(0, r_i).boxed()
.flatMap(i -> IntStream.range(0, r_j).boxed()
.flatMap(j -> IntStream.range(0, r_k)
.mapToObj(k -> new A(i, j, k))))
.collect(Collectors.toList());