In Java vereinfacht die for-each-Schleife den Durchlaufprozess jeder Sammlung oder jedes Arrays, aber nicht jeder Java-Programmierer kennt einige Details der for-each-Schleife, die in diesem Artikel beschrieben werden. Im Gegensatz zu anderen in Java 5 veröffentlichten Begriffen: Alias-veröffentlichte Generika, automatische Kapselung und variadische Parameter, verwenden Java-Entwickler for-each-Schleifen häufiger als jede andere Funktion, aber wenn sie gefragt werden, wie fortgeschritten for-each-Schleifen funktionieren oder was die grundlegenden sind Anforderungen bei der Verwendung einer Sammlung in einer for-each-Schleife kann nicht jeder beantworten.
Dieses Tutorial und Beispiel zielt darauf ab, diese Lücke zu schließen, indem es sich mit einigen interessanten Rätseln in for-each-Schleifen befasst. Okay, gehen wir nicht ins Detail, werfen wir einen Blick auf unser erstes Problem mit der Java5-for-each-Schleife.
Erweiterte Schleifenfrage 1
Betrachten Sie den folgenden Code, der einen benutzerdefinierten Aggregator oder eine Sammlungsklasse durchläuft. Was wird dieser Code ausgeben, unabhängig davon, ob er eine Ausnahme oder einen Compilerfehler auslöst?
Kopieren Sie den Codecode wie folgt:
Pakettest;
/**
* Java-Klasse, um zu zeigen, wie die for-each-Schleife in Java funktioniert
*/
öffentliche Klasse ForEachTest {
public static void main(String args[]){
CustomCollection<String> myCollection = new CustomCollection<String>();
myCollection.add("Java");
myCollection.add("Scala");
myCollection.add("Groovy");
//Was bewirkt dieser Code? Er druckt die Sprache, löst eine Ausnahme aus oder verursacht einen Fehler bei der Kompilierung
for(String-Sprache: myCollection){
System.out.println(Sprache);
}
}
}
Nachfolgend finden Sie unsere CustomCollection-Klasse, eine generische Klasse, die wie jede andere Collection-Klasse auf einer ArrayList basiert und Methoden zum Hinzufügen und Entfernen von Elementen zur Collection bereitstellt.
Kopieren Sie den Codecode wie folgt:
Pakettest;
öffentliche Klasse CustomCollection<T>{
privater ArrayList<T>-Bucket;
öffentliche CustomCollection(){
Bucket = new ArrayList();
}
public int size() {
return Bucket.size();
}
öffentlicher boolescher Wert isEmpty() {
return Bucket.isEmpty();
}
öffentlicher boolescher Wert enthält(T o) {
return Bucket.contains(o);
}
public boolean add(T e) {
return Bucket.add(e);
}
public boolean remove(T o) {
return Bucket.remove(o);
}
}
Antwort:
Der obige Code lässt sich nicht kompilieren, da unsere CustomCollection-Klasse die java.lang.Iterable-Schnittstelle nicht implementiert. Der Fehler bei der Kompilierung lautet wie folgt:
Kopieren Sie den Codecode wie folgt:
Ausnahme im Thread „main“ java.lang.RuntimeException: Nicht kompilierbarer Quellcode – for-each nicht auf Ausdruckstyp anwendbar
Erforderlich: Array oder java.lang.Iterable
gefunden: test.CustomCollection
bei test.ForEachTest.main(ForEachTest.java:24)
Eine interessante Tatsache, die man daraus lernen kann, ist, dass die for-each-Schleife nur für Java-Array- und Collection-Klassen gilt, die die Iterable-Schnittstelle implementieren, und da alle integrierten Collection-Klassen die java.util.Collection-Schnittstelle implementieren und Iterable geerbt haben, ist dies der Fall Ein oft übersehenes Detail ist in der Typdeklaration der Collection-Schnittstelle „public interface Collection Extens Iterable“ zu sehen. Um das oben genannte Problem zu lösen, können Sie CustomCollection einfach die Collection-Schnittstelle implementieren lassen oder AbstractCollection erben, die standardmäßige universelle Implementierung und zeigt, wie abstrakte Klassen und Schnittstellen für mehr Flexibilität gleichzeitig verwendet werden können. Schauen wir uns nun das zweite Rätsel der for-each-Schleife an:
Die zweite Schwierigkeit bei Java-for-each-Schleifen:
Das folgende Codebeispiel löst eine ConcurrentModificationException aus. Hier verwenden wir den Standard-Iterator und die for-each-Schleife, um die ArrayList zu durchlaufen und dann die Elemente zu löschen. Sie müssen herausfinden, welcher Codeabschnitt eine ConcurrentModificationException auslöst und warum. Beachten Sie, dass die Antwort beides, keines oder das eine oder das andere sein könnte.
Kopieren Sie den Codecode wie folgt:
Pakettest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Java-Klasse zur Demonstration der inneren Funktionsweise der for-each-Schleife in Java
* @Autor Javin Paul
**/
öffentliche Klasse ForEachTest2 {
public static void main(String args[]){
Collection<String> list = new ArrayList<String>();
list.add("Android");
list.add("iPhone");
list.add("Windows Mobile");
// Welcher Code wird ConcurrentModificationException auslösen, beide,
// keiner oder einer von ihnen
// Beispiel 1
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String lang = itr.next();
list.remove(lang);
}
//Beispiel 2
for(String language: list){
list.remove(Sprache);
}
}
}
Ungefähr 70 % der Java-Entwickler werden sagen, dass der erste Codeblock eine ConcurrentModificationException-Ausnahme auslöst, weil wir zum Löschen von Elementen nicht die Remove-Methode des Iterators verwenden, sondern die Methode „remove()“ von ArrayList. Allerdings würden nicht viele Java-Entwickler sagen, dass das gleiche Problem bei der for-each-Schleife auftritt, da wir hier keinen Iterator verwenden. Tatsächlich löst das zweite Codefragment auch eine ConcurrentModificationException aus, was nach der Lösung der ersten Verwirrung offensichtlich wird. Da die for-each-Schleife intern einen Iterator verwendet, um die Sammlung zu durchlaufen, ruft sie auch Iterator.next() auf, das nach Änderungen (von Elementen) sucht und eine ConcurrentModificationException auslöst. Sie können dies an der Ausgabe unten erkennen, die Sie erhalten, wenn Sie das zweite Snippet ausführen, nachdem Sie das erste Snippet auskommentiert haben.
Kopieren Sie den Codecode wie folgt:
Ausnahme im Thread „main“ java.util.ConcurrentModificationException
bei java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
bei java.util.AbstractList$Itr.next(AbstractList.java:343)
bei test.ForEachTest2.main(ForEachTest2.java:34)
Das ist alles über die Java5 for-each-Schleife. Wir haben viele Probleme gesehen, die Java-Programmierer haben, wenn sie Code schreiben, der über eine Collection-Klasse iteriert, insbesondere wenn sie über eine Collection iterieren und gleichzeitig Elemente löschen. Denken Sie daran, immer die Methode „remove“ des Iterators zu verwenden, wenn Sie Objekte aus einer Sammlung (z. B. einer Map, einem Set oder einer Liste) entfernen. Denken Sie auch daran, dass die for-each-Schleife nur syntaktischer Zucker (syntaktischer Zucker) zusätzlich zur Standardverwendung von ist Nur Standard-Iterator-Code.
Anmerkung des Übersetzers: Syntaktischer Zucker, auch mit Zucker überzogene Grammatik übersetzt, ist ein vom britischen Informatiker Peter J. Landin erfundener Begriff, der sich auf eine bestimmte Art von Grammatik bezieht, die Computersprachen hinzugefügt wird. Die Syntax hat keinen Einfluss auf die Funktionalität der Sprache, erleichtert aber die Verwendung für Programmierer. Im Allgemeinen kann die Verwendung von Syntax Sugar die Lesbarkeit des Programms verbessern und dadurch die Wahrscheinlichkeit von Programmcodefehlern verringern.