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, але це може бути не причиною.