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()
- If
Iterator.hasNext()
: вызывает Iterator.next()
и продолжает цикл
Что касается того, «почему этот бесполезный цикл не оптимизируется из скомпилированного кода? Мы видим, что он ничего не делает с элементом списка»: хорошо, вы можете написать свой повторяемый код, .iterator()
имеющий побочные эффекты. или так, что .hasNext()
имеет побочные эффекты или значимые последствия.
Вы можете легко представить, что итератор, представляющий прокручиваемый запрос из базы данных, может сделать что-то существенное .hasNext()
(например, связаться с базой данных или закрыть курсор, потому что вы достигли конца набора результатов).
Таким образом, хотя мы можем доказать, что в теле цикла ничего не происходит ... это дороже (неразрешимо?) Доказать, что ничего существенного / последовательного не происходит, когда мы выполняем итерацию. Компилятор должен оставить это пустое тело цикла в программе.
Лучшее, на что мы могли надеяться, это предупреждение компилятора . Интересно , что javac -Xlint:all Whatever.java
это не предупреждает нас об этом пустом теле цикла. IntelliJ IDEA делает, хотя. По общему признанию я настроил IntelliJ для использования Eclipse Compiler, но это не может быть причиной этого.