基准测试:Java 8 Lambda和流如何使您的代码慢5倍
與長期的實現相比,Java 8 lambda和流的性能如何?
Lambda表達式和流在Java 8中受到了熱烈的歡迎。這些是迄今為止很激動人心的功能,很長一段時間以來,它們就已經應用到Java中了。 新的語言功能使我們可以在代碼中采用更具功能性的樣式,并且在其中玩耍也很有趣。 非常有趣,應該是非法的。 然后我們變得可疑 ,并決定對它們進行測試。
我們已經完成了一個簡單的任務,即在ArrayList中找到最大值,并測試了長期的實現與Java 8中可用的新方法的對比。老實說,結果令人驚訝。
Java 8中的命令式與功能式編程
我們喜歡直截了當,所以讓我們看一下結果。 對于此基準,我們創建了一個ArrayList,為其中填充了100,000個隨機整數,并實現了7種不同的方式來遍歷所有值以找到最大值。 這些實現分為兩類:具有Java 8中引入的新語言功能的功能樣式和具有長期Java方法的命令式樣式。
這是每種方法花費的時間:
**記錄的最大錯誤是parallelStream上的0.042,完整的結果輸出可在該文章的底部找到
外賣
等一下,我們到底在這里測試了什么?
讓我們快速瀏覽一下每種方法,從最快到最慢:
命令式
forMaxInteger() –使用簡單的for循環和int索引遍歷列表:
public int forMaxInteger() {int max = Integer.MIN_VALUE;for (int i = 0; i < size; i++) {max = Integer.max(max, integers.get(i));}return max; }iteratorMaxInteger() –使用迭代器遍歷列表:
public int iteratorMaxInteger() {int max = Integer.MIN_VALUE;for (Iterator<Integer> it = integers.iterator(); it.hasNext(); ) {max = Integer.max(max, it.next());}return max; }forEachLoopMaxInteger() –丟失迭代器,并使用For-Each循環遍歷列表(不要誤解為Java 8 forEach):
public int forEachLoopMaxInteger() {int max = Integer.MIN_VALUE;for (Integer n : integers) {max = Integer.max(max, n);}return max; }功能風格
parallelStreamMaxInteger() –在并行模式下使用Java 8流瀏覽列表:
public int parallelStreamMaxInteger() {Optional<Integer> max = integers.parallelStream().reduce(Integer::max);return max.get(); }lambdaMaxInteger() –將lambda表達式與流一起使用。 甜蜜的一線:
public int lambdaMaxInteger() {return integers.stream().reduce(Integer.MIN_VALUE, (a, b) -> Integer.max(a, b)); }forEachLambdaMaxInteger() –這對于我們的用例來說有點混亂。 新的Java 8 forEach功能可能最令人討厭的是它只能使用最終變量,因此我們為最終包裝器類創建了一些變通方法,該類可以訪問我們正在更新的最大值:
public int forEachLambdaMaxInteger() {final Wrapper wrapper = new Wrapper();wrapper.inner = Integer.MIN_VALUE;integers.forEach(i -> helper(i, wrapper));return wrapper.inner.intValue(); }public static class Wrapper {public Integer inner; }private int helper(int i, Wrapper wrapper) {wrapper.inner = Math.max(i, wrapper.inner);return wrapper.inner; }順便說一句,如果我們已經在談論forEach,請查看這個StackOverflow答案,我們就其一些缺點提供了一些有趣的見解。
streamMaxInteger() –使用Java 8流瀏覽列表:
public int streamMaxInteger() {Optional<Integer> max = integers.stream().reduce(Integer::max);return max.get(); }優化基準
遵循本文的反饋意見,我們創建了基準的另一個版本。 與原始代碼的所有差異都可以在此處查看 。 結果如下:
TL; DR:更改摘要
感謝Patrick Reinhart , Richard Warburton , Yan Bonnel , Sergey Kuksenko , Jeff Maxwell , Henrik Gustafsson以及所有在Twitter上發表評論的人!
基礎
為了運行此基準測試,我們使用了Java Microbenchmarking Harness JMH。 如果您想了解更多有關如何在自己的項目中使用它的信息, 請查看這篇文章 ,我們將通過動手示例來了解它的一些主要功能。
基準配置包括JVM的2個分支,5個預熱迭代和5個測量迭代。 這些測試是使用Java 8u66和JMH 1.11.2在c3.xlarge Amazon EC2實例(4個vCPU,7.5 Mem(GiB),2 x 40 GB SSD存儲)上運行的。 完整的源代碼可在GitHub上找到 ,您可以在此處查看原始結果輸出。
話雖這么說,但有一點免責聲明:基準往往非常危險,要正確地制定基準則非常困難。 盡管我們嘗試以最準確的方式運行它,但始終建議您先花一點鹽。
最后的想法
使用Java 8時,要做的第一件事是嘗試使用lambda表達式和流。 但是要當心:感覺真的很好,很甜,所以您可能會上癮! 我們已經看到,堅持使用迭代器和for-each循環的更傳統的Java編程風格,明顯優于Java 8提供的新實現。當然,情況并非總是如此,但是在這個非常常見的示例中,它表明可以大約差5倍。 如果它影響系統的核心部分或創建新的瓶頸,這會變得非常可怕。
翻譯自: https://www.javacodegeeks.com/2015/11/benchmark-java-8-lambdas-streams-can-make-code-5-times-slower.html
總結
以上是生活随笔為你收集整理的基准测试:Java 8 Lambda和流如何使您的代码慢5倍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何检测是否被拉黑(如何检测是否被ddo
- 下一篇: jsf 自定义属性_必填字段的自定义JS