foreach
verwendet sowieso Iteratoren unter der Haube. Es ist wirklich nur syntaktischer Zucker.
Betrachten Sie das folgende Programm:
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) {
}
}
}
Lassen Sie uns kompilieren es mit javac Whatever.java
,
und lesen Sie den zerlegten Bytecode main()
, mit 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
Wir können sehen, dass foreach
sich das zu einem Programm zusammensetzt, das:
- Erstellt einen Iterator mit
List.iterator()
- If
Iterator.hasNext()
: ruft Iterator.next()
die Schleife auf und setzt sie fort
Was "Warum wird diese nutzlose Schleife nicht aus dem kompilierten Code heraus optimiert? Wir können sehen, dass sie nichts mit dem Listenelement zu tun hat": Nun, es ist Ihnen möglich, Ihre iterierbare Schleife so zu codieren, dass sie .iterator()
Nebenwirkungen hat , oder so, das .hasNext()
hat Nebenwirkungen oder bedeutsame Konsequenzen.
Sie können sich leicht vorstellen, dass eine iterable Darstellung einer scrollbaren Abfrage aus einer Datenbank dramatische .hasNext()
Auswirkungen hat (z. B. Kontaktaufnahme mit der Datenbank oder Schließen eines Cursors, weil Sie das Ende der Ergebnismenge erreicht haben).
Obwohl wir also beweisen können, dass im Schleifenkörper nichts passiert, ist es teurer (unlösbar?) Zu beweisen, dass beim Iterieren nichts Sinnvolles / Konsequenzielles passiert. Der Compiler muss diesen leeren Schleifenkörper im Programm belassen.
Das Beste, auf das wir hoffen können, ist eine Compiler- Warnung . Es ist interessant, dass javac -Xlint:all Whatever.java
uns nicht vor diesem leeren Schleifenkörper gewarnt wird. IntelliJ IDEA tut dies jedoch. Zugegeben, ich habe IntelliJ für die Verwendung von Eclipse Compiler konfiguriert, aber das ist möglicherweise nicht der Grund dafür.