2009-05-24 41 views
22

我有這樣的事情:的Java的foreach效率

Map<String, String> myMap = ...; 

for(String key : myMap.keySet()) { 
    System.out.println(key); 
    System.out.println(myMap.get(key)); 
} 

所以是myMap.keySet()foreach循環調用一次? 我認爲這是,但希望你的意見。

我想如果以這種方式(myMap.keySet())使用的foreach知道有性能上的影響,或者是相同的:

Set<String> keySet = myMap.keySet(); 
for (String key : keySet) { 
    ... 
} 
+0

(增強型for循環的語法有點兒回到前面。) – 2009-05-24 20:40:40

+2

我不知道是否同意調用這個過早的優化。理解編譯器在你的代碼中做什麼是合理的。我們也不知道他的項目在哪個階段(如果他甚至在一個項目上工作,而不是在學術上問),他是這樣問的。它可能在最後。 – 2009-07-30 20:28:19

+0

對於這個問題。 – user12458 2013-07-20 20:52:59

回答

65

如果您想絕對肯定,然後編譯它並反編譯並比較。我這樣做有以下來源:

public void test() { 
    Map<String, String> myMap = new HashMap<String, String>(); 

    for (String key : myMap.keySet()) { 
    System.out.println(key); 
    System.out.println(myMap.get(key)); 
    } 

    Set<String> keySet = myMap.keySet(); 
    for (String key : keySet) { 
    System.out.println(key); 
    System.out.println(myMap.get(key)); 
    } 
} 

,當我反編譯的類文件與Jad,我得到:

public void test() 
{ 
    Map myMap = new HashMap(); 
    String key; 
    for(Iterator iterator = myMap.keySet().iterator(); iterator.hasNext(); System.out.println((String)myMap.get(key))) 
    { 
     key = (String)iterator.next(); 
     System.out.println(key); 
    } 

    Set keySet = myMap.keySet(); 
    String key; 
    for(Iterator iterator1 = keySet.iterator(); iterator1.hasNext(); System.out.println((String)myMap.get(key))) 
    { 
     key = (String)iterator1.next(); 
     System.out.println(key); 
    } 
} 

因此,有你的答案。它被用for循環形式調用一次。

+10

+1用於編譯器做什麼的實際證明 – 2009-05-25 00:36:44

5

是的,這就是所謂的只有一次無論哪種方式

-2

我相信這是編譯器優化,每循環條目只運行一次。

9

keySet()只被調用一次。 「增強for循環」基於Iterable接口,它用於獲取Iterator,然後將其用於循環。甚至不可能以任何其他方式遍歷Set,因爲沒有索引或任何可以獲取單個元素的東西。

但是,你真正應該做的就是完全放棄這種微觀優化的擔憂 - 如果你有真正的性能問題,那麼你有99%的機會是你從來沒有想過的。

35

它只被調用一次。實際上它使用一個迭代器來完成這個技巧。

此外,你的情況,我認爲你應該使用

for (Map.Entry<String, String> entry : myMap.entrySet()) 
{ 
    System.out.println(entry.getKey()); 
    System.out.println(entry.getValue()); 
} 

,以避免在地圖上每一次搜索。

7

答案是在Java語言規範,不需要編譯:)這是我們能讀到the enhanced for statement

增強的for語句的 形式:

EnhancedForStatement: 
     for (VariableModifiersopt Type Identifier: Expression) Statement 

該表達式必須具有類型 Iterable,否則它必須是 數組類型(第10.1節),或發生編譯時 錯誤。

增強for聲明(第14節)的形式參數部分中聲明 的局部變量的作用域。14)是 所包含的聲明

增強for 句話的意思是通過翻譯給到 基本for聲明。

如果Expression類型是 亞型Iterable,然後讓I是 表達 表達式的類型。iterator()。增強for語句等效 到一個基本for語句 形式:

for (I #i = Expression.iterator(); #i.hasNext();) { 

     VariableModifiersopt Type Identifier = #i.next(); 
    Statement 
} 

#i是一個編譯器生成的 標識符是從任何 其他標識符(不同編譯器生成的 或以其它方式)在範圍(§6.3) 處發生增強的 語句的位置。

否則,表達必然 有一個陣列類型,T[]。假設L1 ... Lm 是 增強for語句之前緊接的 標籤的序列(可能爲空)。然後增強的for語句 的 意義由以下基本for 語句中給出:

T[] a = Expression; 
L1: L2: ... Lm: 
for (int i = 0; i < a.length; i++) { 
     VariableModifiersopt Type Identifier = a[i]; 
     Statement 
} 

一個是編譯器生成的 標識符可從任何 其他標識符不同(編譯器生成的 或其他),其範圍在 點,其中增強型語句 發生。

在你的情況,myMap.keySet()返回Iterable亞型讓你增強for語句等效於以下基本for聲明:因此

for (Iterator<String> iterator = myMap.keySet().iterator(); iterator.hasNext();) { 
    String key = iterator.next(); 

    System.out.println(key); 
    System.out.println(myMap.get(key)); 
} 

而且myMap.keySet()只調用一次。