2013-08-29 39 views
31

請考慮以下情況。For-each vs迭代器。哪個更好選擇

List<String> list = new ArrayList<>(); 

現在我爲此列表添加String值。

我使用以下方法去列表中的每個元素。

選項單用for-each

for (String i : list) { 
     System.out.println(i); 
    } 

選項二用Iterator

Iterator it=list.iterator(); 
while (it.hasNext()){ 
    System.out.println(it.next()); 
} 

我只是想知道是否有任何性能上的優勢,如果我使用for-each代替Iterator。現在在Java中使用Iterator還有一種不好的做法嗎?

+4

我想每個使用迭代 –

+0

可能重複http://stackoverflow.com/questions/2113216/which-is-more-efficient-a-for-each-loop-or-an-iterator –

回答

68

for-each是使用iterators(方法2)的句法糖。

如果您需要修改循環中的集合,則可能需要使用iterators。第一種方法會拋出異常。

for (String i : list) { 
    System.out.println(i); 
    list.remove(i); // throws exception 
} 

Iterator it=list.iterator(); 
while (it.hasNext()){ 
    System.out.println(it.next()); 
    it.remove(); // valid here 
} 
+7

中當然,要記住,添加/刪除集合中的項目並不是好習慣,因爲您突出強調了這一點。 – Jeremy

1

簡單的答案:沒有和沒有。

在內部,for-each循環創建一個Iterator來遍歷集合。

明確使用Iterator的優點是您可以訪問Iterator的方法。

9

for-each是一種高級循環構造。它在內部創建一個迭代器並遍歷集合。只有在for-each結構上使用實際Iterator對象的可能優點是,您可以使用Iterator的方法(如.remove())修改您的集合。在迭代過程中不使用迭代器的方法修改集合將產生一個ConcurrentModificationException.

+2

* Can * not「will」會導致ConcurrentModificationException –

+0

這裏有一個困惑,如果每個使用增強使用Iterator內部爲什麼迭代時元素的刪除有限制? – shaun

+0

@shaun,因爲你沒有訪問它:) –

14

區別主要是語法糖,不同之處在於迭代器可以從正在迭代的集合中移除項目。從技術上講,增強的for循環允許你遍歷任何Iterable,它至少包括集合和數組。

不要擔心性能差異。這種微觀優化是無關緊要的分心。如果您需要隨時移除項目,請使用迭代器。否則,對於循環傾向於使用更多的只是因爲他們更可讀即:

for (String s : stringList) { ... } 

VS:

for (Iterator<String> iter = stringList.iterator(); iter.hasNext();) { 
    String s = iter.next(); 
    ... 
} 
0

如果你想更換您的列表項,我會去老同學用for循環

for (int nIndex=0; nIndex < list.size(); nIndex++) { 
    Obj obj = (Obj) list.get(nIndex); 

    // update list item 
    list.set(nIndex, obj2); 
} 
3
+0

爲什麼你認爲使用list.foreach()更好?在這樣的feaeach()方法中,你不能修改一個extern var並且不得不將它複製爲final或者將其包裝在一個數組中。 –

0

foreach使用迭代引擎蓋下反正。它真的只是語法糖。

考慮下面的程序:

import java.util.List; 
import java.util.ArrayList; 

public class Whatever { 
    private final List<Integer> list = new ArrayList<>(); 
    public void main() { 
     for(Integer i : list) { 
     } 
    } 
} 

讓我們javac Whatever.java編譯它,
而閱讀的main()拆解字節碼,使用javap -c Whatever

public void main(); 
    Code: 
    0: aload_0 
    1: getfield  #4     // Field list:Ljava/util/List; 
    4: invokeinterface #5, 1   // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 
    9: astore_1 
    10: aload_1 
    11: invokeinterface #6, 1   // InterfaceMethod java/util/Iterator.hasNext:()Z 
    16: ifeq   32 
    19: aload_1 
    20: invokeinterface #7, 1   // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 
    25: checkcast  #8     // class java/lang/Integer 
    28: astore_2 
    29: goto   10 
    32: return 

我們可以看到,foreach編譯成一個程序,其中:

  • 創建使用List.iterator()
  • 如果Iterator.hasNext()迭代:調用Iterator.next(),並繼續循環

至於「爲什麼不這樣無用的循環得到優化了編譯的代碼嗎?我們可以看到它不會對列表項「做任何事情」:好吧,您可能會編碼您的迭代器,使得.iterator()有副作用,或者因此.hasNext()有副作用或有意義的後果

你可以很容易地想象,代表數據庫中可滾動查詢的迭代器可能會在.hasNext()上做一些戲劇性的事情(如聯繫數據庫或關閉遊標,因爲你已經到達結果集的末尾)

因此,儘管我們可以證明在循環體中沒有任何事情發生......它是更昂貴的(難以處理的)來證明當我們迭代時沒有什麼有意義的或必然的事情發生,編譯器必須在程序中保留這個空的循環體

我們希望的最好的方法是編譯器警告。有趣的是,javac -Xlint:all Whatever.java確實不是而是警告我們這個空的循環體。 IntelliJ IDEA雖然。不可否認,我已經配置IntelliJ來使用Eclipse編譯器,但這可能不是原因。

enter image description here

0

下面是簡單的代碼片段來檢查For-each性能VS Iterator VS forArrayList<String>遍歷,對Java版本8

 long MAX = 2000000; 

     ArrayList<String> list = new ArrayList<>(); 

     for (long i = 0; i < MAX; i++) { 

      list.add("" + i); 
     } 

     /** 
     * Checking with for each iteration. 
     */ 
     long A = System.currentTimeMillis(); 

     for (String data : list) { 
      // System.out.println(data); 
     } 

     long B = System.currentTimeMillis(); 
     System.out.println(B - A + "ms"); 

     /** 
     * Checking with Iterator method 
     */ 

     Iterator<String> iterator = list.iterator(); 
     while (iterator.hasNext()) { 
      iterator.next(); 
      // System.out.println(iterator.next()); 
     } 

     long C = System.currentTimeMillis(); 
     System.out.println(C - B + "ms"); 

     /** 
     * Checking with normal iteration. 
     */ 
     for (int i = 0; i < MAX; i++) { 
      list.get((int) (i % (MAX - i))); 
      // System.out.println(list.get(i)); 
     } 

     long D = System.currentTimeMillis(); 
     System.out.println(D - C + "ms"); 

平均輸出值執行:

19ms 
9ms 
27ms 

結果分析: Iterator(9ms的)< For-each(19ms)< For(27ms)

這裏Iterator具有最佳性能For有至少一個演出。然而For-each表現介於兩者之間。