2016-11-09 57 views
2

考慮一個簡單的POJO:流::地圖()效率多次調用

class Foo { 
    private String id; 
    // Other fields, getters & setters ommited 
} 

如果我有一個List<Foo>,並希望與生產轉化爲int的所有ID的Stream<Integer>,我有什麼可以期待性能方面比較時,這種方法:

fooList 
    .stream() 
    .map(foo -> Integer.parseInt(foo.getId())) 

...這一個:

fooList 
    .stream() 
    .map(Foo::getId) 
    .map(Integer::parseInt) 
+6

您可以隨時[發現](HTTP:/ /stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java)。 –

+0

感謝您的提示,我會把我的懶惰放在一邊,並與JMH一起玩 – everton

回答

4

可能是第二個(將必須測量),因爲它會將方法「引入」調用網站,因爲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(); 
    } 
} 
+0

這很有趣,設計這些流水線轉換的方式似乎是一種很好的做法。謝謝! – everton

+1

我不知道什麼「*,因爲它會」調用「方法到調用網站,因爲invokedynamic *」應該是這個意思。我沒有看到任何重大性能差異的原因。請注意,在您的基準測試結果中,誤差與兩個結果之間的測量差異具有相同的量級。 – Holger