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