首頁>科技>

Which is Faster For Loop or For-each in Java

對於Java中的For循環和Foreach,哪個更快

通過本文,您可以瞭解一些集合遍歷技巧。

Java遍歷集合有兩種方法。一個是最基本的for循環,另一個是jdk5引入的for each。通過這種方法,我們可以更方便地遍歷數組和集合。但是你有沒有想過這兩種方法?哪一個遍歷集合更有效?

for-each實現方法

For-each不是一種新語法,而是Java的語法糖。在編譯時,編譯器將此代碼轉換為迭代器實現,並將其編譯為字節碼。

語法糖:語法糖(Syntactic sugar),也譯為糖衣語法,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用。通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會。

我們可以通過執行命令javap-verbose-Testforeach反編譯以下編譯代碼:

public class TestForeach {List<Integer> integers;public void testForeach(){ for(Integer i : integers){ }}}

獲得的詳細字節碼如下:

public void testForeach();descriptor: ()Vflags: ACC_PUBLICCode:  stack=1, locals=3, args_size=1  0: aload_0  1: getfield  #2// Field integers:Ljava/util/List;  4: invokeinterface #3,  1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;  9: astore_1 10: aload_1 11: invokeinterface #4,  1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq   32 19: aload_1 20: invokeinterface #5,  1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #6// class java/lang/Integer 28: astore_2 29: goto   10 32: return  LineNumberTable: line 11: 0 line 13: 29 line 14: 32  LocalVariableTable: Start  Length  Slot  Name   Signature290 2 i   Ljava/lang/Integer; 0  33 0  this   Ltest/TestForeach;}

此字節碼的一般含義是使用getfileld命令來獲取integers變量並且調用List.iterator來獲取迭代器實例和調用iterator.hasNext。如果返回true,調用iterator.next方法。

請看,這是迭代器遍歷集合的實現邏輯。

基準測試

現在讓我們使用for循環方法和for-each方法進行測試。

ublic class ForLoopTest {public static void main(String[] args) { List<Integer> arrayList = new ArrayList<>(); for (int i = 0; i < 10000000; i++) { arrayList.add(i); } long arrayListStartTime = System.currentTimeMillis(); for (int i = 0; i < arrayList.size(); i++) { arrayList.get(i); } long arrayListCost =System.currentTimeMillis()-arrayListStartTime; System.out.println("ArrayList for loop traversal cost: "+ arrayListCost); long arrayListForeachStartTime = System.currentTimeMillis(); for (Integer integer : arrayList) { } long arrayListForeachCost =System.currentTimeMillis()-arrayListForeachStartTime; System.out.println("ArrayList foreach traversal cost: "+ arrayListForeachCost);

這是測試結果:

如你所見,結果是顯而易見的。對於ArrayList,使用For循環方法的性能優於For each方法。

我們可以說for循環比for-each好嗎?

答案是否定的。在下一個基準測試中,我們將ArrayList更改為LinkedList。同樣,這裡是測試結果。

原因分析

一些初學者可能想知道為什麼ArrayList使用for循環方法遍歷得更快,而LinkedList則更慢,速度也非常慢?

這由ArrayList和LinkedList數據結構決定。ArrayList底層使用數組存儲元素。數組是連續的內存空間。數據可以通過索引獲得。時間複雜度為O(1),因此速度很快。

LinkedList的底層是一個雙向鏈表。使用for循環實現遍歷,每次都需要從鏈表的頭節點開始。時間複雜度為O(n*n)。

結論

  1. 使用ArrayList時,for循環方法更快,因為for-each由迭代器實現,並且需要執行併發修改驗證。
  2. 使用LinkedList時,for-each比for循環快得多,因為LinkedList是通過使用雙向鏈表實現的。每個尋址都需要從頭節點開始。如果我們需要遍歷LinkedList,我們需要避免使用for循環。
  3. 使用迭代器模式,for-each不需要關心集合的具體實現。如果需要替換集合,無需修改代碼即可輕鬆替換。
9
最新評論
  • 整治雙十一購物亂象,國家再次出手!該跟這些套路說再見了
  • 萬年未有之大變局,我們必將進入共產主義社會