Probably the second (will have to measure), since it will "bring" the method to the call site because of the invokedynamic.
Or, I could be wrong, because of the extra map operation and the infrastructure needed to handle that. Will update the post with some jmh results.
Indeed (according to the tests I have), the method reference is faster:
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
And here is the code :
@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();
}
}