我有這樣的for-each循環:這個代碼是否會在每次迭代中被評估?
for (Component c : container.getComponents()) {
// Loop code
}
是getComponents
呼籲每個迭代?是否有意義調用getComponents
的外觀和唯一的工作緩存陣列之前?
我有這樣的for-each循環:這個代碼是否會在每次迭代中被評估?
for (Component c : container.getComponents()) {
// Loop code
}
是getComponents
呼籲每個迭代?是否有意義調用getComponents
的外觀和唯一的工作緩存陣列之前?
沒有,getComponents()纔會被調用一次。
這是等價的:
for (Iterator<Component> iterator = container.getComponents().getIterator();
iterator.hasNext();)
{
Component c = iterator.next();
...
}
從section 14.14.2 of the Java Language Specification:
增強的for語句的形式:
EnhancedForStatement:
for (VariableModifiersopt Type Identifier: Expression) Statement
的表達必須具有類型可迭代否則它必須是一個數組類型(§10.1),>或編譯時發生錯誤。 在增強對 聲明(§14.14)的FormalParameter部分聲明的局部變量的範圍是所包含的聲明
的增強for語句被翻譯成給出一個基本的
for
語句的含義。如果Expression的類型是
Iterable
的子類型,那麼讓我是 表達式Expression.iterator()
的類型。窗體的基本for
聲明增強的for語句是等價的:for (I #i = Expression.iterator(); #i.hasNext();) { VariableModifiersopt Type Identifier = #i.next(); Statement }
我想不到的是,在編譯時,將它轉換爲是一個「長手」的循環,如在使用的for(int i = 0 ....
是不是foreach循環剛實際字節碼轉換一樣做「長手」編程節省時間?
總之,getComponent()應該只被調用一次
不,這不是foreach循環的工作方式(儘管getComponent()只會被調用一次)。 – 2009-10-09 13:27:12
這不值得-1(你給出的實際答案是正確的,雖然之前的假設是錯誤的),所以這裏是+1。 – 2009-10-09 13:31:08
getComponents將被調用一次,並且將返回一個Iterator此迭代器將接着使用next()和hasNext()方法被調用。
更新這裏有一點更詳細的嘗試出Skeet Jon Skeet對此答案。
下面的程序演示如何調用iterator
只進行一次,即使有集合中三個項目。
public static void main(String[] args) {
List<String> list = new ArrayList<String>() {
public java.util.Iterator<String> iterator() {
System.out.println("iterator() called");
return super.iterator();
};
};
list.add("a");
list.add("b");
list.add("c");
for (String s : list) {
System.out.println(s);
}
}
輸出:
iterator() called
a
b
c
如果您通過Java反編譯運行它,你會發現下面的代碼:
String s;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(s))
s = (String)iterator.next();
Addtionally,因爲我們從JLS 14.14.1知道for語句的第一部分只執行一次,我們可以放心,迭代器方法不會被多次調用。
Java LanguageSpecification 14.14.2說:
EnhancedForStatement:
for (VariableModifiersopt Type Identifier: Expression) Statement
如果表達式的類型是可迭代的子類型,則讓我是表達Expression.iterator的類型() 。爲形式的語句中的增強的for語句相當於一個基本:
for (I #i = Expression.iterator(); #i.hasNext();) {
VariableModifiersopt Type Identifier = #i.next();
Statement
}
凡#i中是一個編譯器生成的 標識符是從任何其他 標識符(不同編譯器生成的 或否則)位於範圍(第6.3節) 處,發生增強的 語句。
因此,該表達式僅被評估一次(初始化期間)。
Jon,編譯器如何保證getComponents()沒有副作用,並且在每次迭代中不會產生不同的東西? (例如,如果另一個線程更改了組件?)。 – Uri 2009-10-09 13:28:28
它不......但上面的翻譯基本上是它定義的。我會嘗試找到JLS參考。 – 2009-10-09 13:29:37
我的不好。我誤解了源代碼。我認爲OP在詢問是否重新評估for循環中的控制條件。我沒有注意到這是一個for-each。 – Uri 2009-10-09 13:29:53