java lambda::_基准测试:Java 8 Lambda和流如何使您的代码慢5倍
java lambda::
與長(zhǎng)期的實(shí)現(xiàn)相比,Java 8 lambda和流的性能如何?
Lambda表達(dá)式和流在Java 8中受到了熱烈的歡迎。這些是迄今為止很激動(dòng)人心的功能,很長(zhǎng)一段時(shí)間以來(lái),它們就已經(jīng)應(yīng)用到Java中了。 新的語(yǔ)言功能使我們可以在代碼中采用更具功能性的樣式,并且在其中玩耍很有趣。 太有趣了,應(yīng)該是非法的。 然后我們變得可疑 ,并決定對(duì)它們進(jìn)行測(cè)試。
我們已經(jīng)完成了一個(gè)簡(jiǎn)單的任務(wù),即在ArrayList中找到最大值,并測(cè)試了長(zhǎng)期的實(shí)現(xiàn)與Java 8中可用的新方法的對(duì)比。老實(shí)說(shuō),結(jié)果令人驚訝。
Java 8中的命令式與功能式編程
我們喜歡直截了當(dāng),所以讓我們看一下結(jié)果。 對(duì)于此基準(zhǔn),我們創(chuàng)建了一個(gè)ArrayList,為其中填充了100,000個(gè)隨機(jī)整數(shù),并實(shí)現(xiàn)了7種不同的方式來(lái)遍歷所有值以找到最大值。 這些實(shí)現(xiàn)分為兩類(lèi):具有Java 8中引入的新語(yǔ)言功能的功能樣式和具有長(zhǎng)期Java方法的命令式樣式。
這是每種方法花費(fèi)的時(shí)間:
**記錄的最大錯(cuò)誤是parallelStream上的0.042,完整的結(jié)果輸出可在該文章的底部找到
外賣(mài)
等一下,我們到底在這里測(cè)試了什么?
讓我們快速瀏覽一下每種方法,從最快到最慢:
命令式
forMaxInteger() –使用簡(jiǎn)單的for循環(huán)和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循環(huán)遍歷列表(不要誤解為Java 8 forEach):
public int forEachLoopMaxInteger() {int max = Integer.MIN_VALUE;for (Integer n : integers) {max = Integer.max(max, n);}return max; }功能風(fēng)格
parallelStreamMaxInteger() –在并行模式下使用Java 8流瀏覽列表:
public int parallelStreamMaxInteger() {Optional<Integer> max = integers.parallelStream().reduce(Integer::max);return max.get(); }lambdaMaxInteger() –將lambda表達(dá)式與流一起使用。 甜蜜的一線:
public int lambdaMaxInteger() {return integers.stream().reduce(Integer.MIN_VALUE, (a, b) -> Integer.max(a, b)); }forEachLambdaMaxInteger() –對(duì)于我們的用例,這有點(diǎn)混亂。 新的Java 8 forEach功能可能最令人討厭的是它只能使用最終變量,因此我們?yōu)樽罱K包裝器類(lèi)創(chuàng)建了一些變通方法,該類(lèi)訪問(wèn)我們正在更新的最大值:
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; }順便說(shuō)一句,如果我們已經(jīng)在談?wù)揻orEach,請(qǐng)查看這個(gè)StackOverflow答案,我們就其某些缺點(diǎn)提供了一些有趣的見(jiàn)解。
streamMaxInteger() –使用Java 8流瀏覽列表:
public int streamMaxInteger() {Optional<Integer> max = integers.stream().reduce(Integer::max);return max.get(); }優(yōu)化基準(zhǔn)
遵循本文的反饋意見(jiàn),我們創(chuàng)建了基準(zhǔn)的另一個(gè)版本。 與原始代碼的所有差異都可以在此處查看 。 結(jié)果如下:
TL; DR:更改摘要
感謝Patrick Reinhart , Richard Warburton , Yan Bonnel , Sergey Kuksenko , Jeff Maxwell , Henrik Gustafsson以及在Twitter上發(fā)表評(píng)論的每個(gè)人!
基礎(chǔ)
為了運(yùn)行此基準(zhǔn),我們使用了JMH,即Java Microbenchmarking Harness。 如果您想了解更多有關(guān)如何在自己的項(xiàng)目中使用它的信息, 請(qǐng)查看這篇文章 ,我們將通過(guò)動(dòng)手示例來(lái)了解它的一些主要功能。
基準(zhǔn)配置包括2個(gè)JVM分支,5個(gè)預(yù)熱迭代和5個(gè)測(cè)量迭代。 測(cè)試使用Java 8u66和JMH 1.11.2在c3.xlarge Amazon EC2實(shí)例(4個(gè)vCPU,7.5 Mem(GiB),2 x 40 GB SSD存儲(chǔ))上運(yùn)行。 完整的源代碼可在GitHub上找到 ,您可以在此處查看原始結(jié)果輸出。
話雖這么說(shuō),但有一點(diǎn)免責(zé)聲明:基準(zhǔn)往往非常危險(xiǎn),要正確地制定基準(zhǔn)則非常困難。 雖然我們嘗試以最準(zhǔn)確的方式運(yùn)行它,但始終建議您花一點(diǎn)時(shí)間來(lái)獲取結(jié)果。
最后的想法
使用Java 8時(shí),要做的第一件事是嘗試使用lambda表達(dá)式和流。 但是要當(dāng)心:它感覺(jué)真的很好,很甜,所以您可能會(huì)上癮! 我們已經(jīng)看到,堅(jiān)持使用迭代器和for-each循環(huán)的更傳統(tǒng)的Java編程風(fēng)格,明顯優(yōu)于Java 8提供的新實(shí)現(xiàn)。當(dāng)然,情況并非總是如此,但是在這個(gè)非常常見(jiàn)的示例中,它表明可以大約差5倍。 如果它影響系統(tǒng)的核心部分或創(chuàng)建新的瓶頸,這會(huì)變得非常可怕。
翻譯自: https://www.javacodegeeks.com/2015/11/benchmark-java-8-lambdas-streams-can-make-code-5-times-slower.html
java lambda::
總結(jié)
以上是生活随笔為你收集整理的java lambda::_基准测试:Java 8 Lambda和流如何使您的代码慢5倍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 古巴比伦乘法_古巴平台中的通用过滤器–类
- 下一篇: 在Java中使用FileChannel和