日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

高效遍历Java容器

發(fā)布時(shí)間:2025/3/21 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 高效遍历Java容器 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

通過(guò)本文,你可以更深入的學(xué)習(xí) Java 語(yǔ)言中 forEach 語(yǔ)法的知識(shí),以及它和 C 語(yǔ)言形式的 for 循環(huán)、 Steam API 的對(duì)比。

?

簡(jiǎn)介


Java 程序員經(jīng)常使用容器,比如 ArrayList 和 HashSet。Java 8 中的 lambda 語(yǔ)法和 steaming API 可以讓我們更方便的使用容器。大部分情況下,我們僅僅處理幾千個(gè)元素,也不會(huì)去考慮性能問(wèn)題。但是,在一些極端場(chǎng)景下,如果我們需要遍歷上百萬(wàn)個(gè)元素,性能問(wèn)題就凸顯出來(lái)了。

本文將采用 JMH 計(jì)算每塊代碼的運(yùn)行時(shí)間。

?

forEach vs. C Style vs. Stream API


遍歷是一個(gè)基本的功能。所有編程語(yǔ)言都提供了簡(jiǎn)單的語(yǔ)法,讓程序員去遍歷容器。

Steam API 以一種非常直接的形式來(lái)遍歷容器。

public?List<Integer> streamSingleThread(BenchMarkState state){List<Integer> result =?new?ArrayList<>(state.testData.size());state.testData.stream().forEach(item -> {result.add(item);});return?result; } public?List<Integer> streamMultiThread(BenchMarkState state){List<Integer> result =?new?ArrayList<>(state.testData.size());state.testData.stream().parallel().forEach(item -> {result.add(item);});return?result; }

?

forEach 循環(huán)也很簡(jiǎn)單:

public?List<Integer>?forEach(BenchMarkState state){List<Integer> result =?new?ArrayList<>(state.testData.size());for(Integer item : state.testData){result.add(item);}return?result; }

?

C 語(yǔ)言形式的 for 循環(huán)啰嗦一些,不過(guò)依然很緊湊:

public?List<Integer>?forCStyle(BenchMarkState state){int?size = state.testData.size();List<Integer> result =?new?ArrayList<>(size);for(int?j =?0; j < size; j ++){result.add(state.testData.get(j));}return?result; }

?

以下是性能報(bào)告:

Benchmark ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Mode ?Cnt ? Score ? Error ?Units TestLoopPerformance.forCStyle ? ? ? ? ? avgt ?200??18.068?±?0.074??ms/op TestLoopPerformance.forEach?? ? ? ? ? ? avgt ?200??30.566?±?0.165??ms/op TestLoopPerformance.streamMultiThread ? avgt ?200??79.433?±?0.747??ms/op TestLoopPerformance.streamSingleThread ?avgt ?200??37.779?±?0.485??ms/op

?

使用 C 語(yǔ)言形式的 for 循環(huán),JVM 每次僅僅增加一個(gè)數(shù)字,然后直接從內(nèi)存里讀出數(shù)據(jù)。這使得它非常迅速。但是 forEach 就大不一樣,根據(jù) StackOverFlow 的這篇回答(https://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work/85206#85206),和 Oracle 的文章(https://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html),JVM 需要把 forEach 轉(zhuǎn)換成一個(gè) iterator,然后每個(gè)元素都調(diào)用一次 hasNext() 方法。這就是 forEach 比 C 語(yǔ)言的形式慢一些的原因。

?

哪一個(gè)是遍歷 Set 最高效的方法呢?


我們先定義測(cè)試數(shù)據(jù)集:

@State(Scope.Benchmark) public?static?class?BenchMarkState?{public?Set<Integer> testData =?new?HashSet<>(500000);@Setup(Level.Trial)public?void?doSetup()?{for(int?i =?0; i <?500000; i++){testData.add(Integer.valueOf(i));}}@TearDown(Level.Trial)public?void?doTearDown()?{testData =?new?HashSet<>(500000);}}

?

Java 中的 Set 也支持 Steam API 和 forEach 循環(huán)。參考之前的測(cè)試,如果我們把 Set 轉(zhuǎn)換成 ArrayList,然后遍歷 ArrayList,或許性能會(huì)好一些?

public?List<Integer>?forCStyle(BenchMarkState state){int?size = state.testData.size();List<Integer> result =?new?ArrayList<>(size);Integer[] temp = (Integer[]) state.testData.toArray(new?Integer[size]);for(int?j =?0; j < size; j ++){result.add(temp[j]);}return?result; }

?

如果把 iterator 和 C 語(yǔ)言形式結(jié)合起來(lái)呢?

public?List<Integer>?forCStyleWithIteration(BenchMarkState state){int?size = state.testData.size();List<Integer> result =?new?ArrayList<>(size);Iterator<Integer> iteration = state.testData.iterator();for(int?j =?0; j < size; j ++){result.add(iteration.next());}return?result;}

?

或者,簡(jiǎn)單的遍歷怎么樣?

public?List<Integer>?forEach(BenchMarkState state){List<Integer> result =?new?ArrayList<>(state.testData.size());for(Integer item : state.testData) {result.add(item);}return?result; }

?

這個(gè)主意不錯(cuò),不過(guò)它的效率也不高,因?yàn)槌跏蓟粋€(gè)新的 ArrayList 同樣需要消耗資源。

Benchmark ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Mode ?Cnt ?Score ? Error ?Units TestLoopPerformance.forCStyle ? ? ? ? ? ? ? avgt ?200??6.013?±?0.108??ms/op TestLoopPerformance.forCStyleWithIteration ?avgt ?200??4.281?±?0.049??ms/op TestLoopPerformance.forEach?? ? ? ? ? ? ? ? avgt ?200??4.498?±?0.026??ms/op

?

HashMap (使用 HashMap<E,Object> 的 HashSet) 不是為遍歷所有元素設(shè)計(jì)的。遍歷一個(gè) HashMap 最快的方法是把 Iterator 和 C 語(yǔ)言形式結(jié)合起來(lái),這樣 JVM 就不會(huì)去調(diào)用 hasNext()。

?

結(jié)論


Foreach 和 Steam API 用來(lái)處理集合是很方便的。你可以更快的寫代碼。不過(guò),如果你的系統(tǒng)很穩(wěn)定,性能是一個(gè)主要的考量,你應(yīng)該考慮一下重寫你的循環(huán)。

總結(jié)

以上是生活随笔為你收集整理的高效遍历Java容器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。