Java Stream::map()用于多个调用的效率

Java Stream::map()用于多个调用的效率,java,java-stream,Java,Java Stream,考虑一个简单的POJO: class Foo { private String id; // Other fields, getters & setters ommited } 如果我有一个列表,并且希望生成一个流,其中所有ID都转换为int,那么在比较此方法时,在性能方面我可以期望什么: fooList .stream() .map(foo -> Integer.parseInt(foo.getId())) 。。。关于这一点: fooList

考虑一个简单的POJO:

class Foo {
    private String id;
    // Other fields, getters & setters ommited
}
如果我有一个
列表
,并且希望生成一个
,其中所有ID都转换为
int
,那么在比较此方法时,在性能方面我可以期望什么:

fooList
    .stream()
    .map(foo -> Integer.parseInt(foo.getId()))
。。。关于这一点:

fooList
    .stream()
    .map(Foo::getId)
    .map(Integer::parseInt)
可能是第二个(必须测量),因为它会因为invokedynamic而将方法“带”到调用站点。 或者,我可能错了,因为需要额外的地图操作和处理这一问题所需的基础设施。将用一些jmh结果更新帖子

事实上(根据我的测试),方法参考更快:

Benchmark              Mode  Cnt  Score   Error  Units
MyBenchmark.doubleMap  avgt   20  3.973 ± 0.057  ms/op
MyBenchmark.singleMap  avgt   20  6.222 ± 2.216  ms/op
代码如下:

@State(Scope.Thread)
public class MyBenchmark {

    private List<Foo> singleMapList = new ArrayList<>();

    private List<Foo> doubleMapList = new ArrayList<>();

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public List<Integer> singleMap() {
        return singleMapList.stream().map(foo ->     Integer.parseInt(foo.getId())).collect(Collectors.toList());
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    public List<Integer> doubleMap() {
        return doubleMapList.stream().map(Foo::getId).map(Integer::parseInt).collect(Collectors.toList());
}

    @Setup
    public void setup() {
        for (int i = 0; i < 100_000; i++) {
            singleMapList.add(new Foo("" + i));
            doubleMapList.add(new Foo("" + i));
        }
    }

     public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(MyBenchmark.class.getSimpleName()).forks(1).build();
        new Runner(opt).run();
    }
}
@状态(Scope.Thread)
公共类MyBenchmark{
private List singleMapList=new ArrayList();
私有列表doubleMapList=newArrayList();
@基准
@基准模式(模式平均时间)
@OutputTimeUnit(时间单位毫秒)
公共列表singleMap(){
返回singleMapList.stream().map(foo->Integer.parseInt(foo.getId()).collect(Collectors.toList());
}
@基准
@基准模式(模式平均时间)
@OutputTimeUnit(时间单位毫秒)
公共列表doubleMap(){
返回doubleMapList.stream().map(Foo::getId).map(Integer::parseInt).collect(Collectors.toList());
}
@设置
公共作废设置(){
对于(int i=0;i<100_000;i++){
添加(新的Foo(“+i”);
添加(新的Foo(“+i”);
}
}
公共静态void main(字符串[]args)引发RunnerException{
Options opt=newoptionsBuilder().include(MyBenchmark.class.getSimpleName()).forks(1.build();
new Runner(opt.run();
}
}

你总是可以的。谢谢你的提示,我将把我的懒惰放在一边,玩一玩JMH。这很有趣,以管道方式设计这些流转换似乎是一个很好的实践。谢谢我不知道“由于invokedynamic”,它将“把”方法“带到”调用站点意味着什么。我看不出有任何理由会有显著的性能差异。请注意,在基准测试结果中,误差的大小与两个结果之间的测量差值相同。