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()
(например, связаться с базой данных или закрыть курсор, потому что вы достигли конца набора результатов).
Итак, даже хотя мы можем доказать, что в теле цикла ничего не происходит ... более дорого (неразрешимо?), чтобы доказать, что ничего значимого/косвенного не происходит, когда мы итерируем. Компилятор должен оставить этот пустой цикл в программе.
Лучшее, на что мы могли надеяться, было бы компилятором warning.Интересно, что 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 –