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編譯器,但這可能不是原因。
我想每個使用迭代 –
可能重複http://stackoverflow.com/questions/2113216/which-is-more-efficient-a-for-each-loop-or-an-iterator –