Heim > Java > javaLernprogramm > Detaillierte Erläuterung der for-each-Schleife und Iteration in JAVA

Detaillierte Erläuterung der for-each-Schleife und Iteration in JAVA

高洛峰
Freigeben: 2017-01-21 16:43:06
Original
1405 Leute haben es durchsucht

Beim Erlernen der Sammlung in Java ist mir aufgefallen, dass die Root-Schnittstelle Collection der Sammlungsebene die Iterable-Schnittstelle implementiert (befindet sich im java.lang-Paket). Durch die Implementierung dieser Schnittstelle kann das Objekt zum Ziel von „ werden. foreach“-Anweisung und die einzige in der Schnittstelle implementierte Methode besteht darin, einen Iterator zurückzugeben, der über eine Menge von Elementen vom Typ T iteriert.

1. Iterator Iterator

Schnittstelle: Iterator

public interface Iterator<E>{
  boolean hasNext();
 E next();
 void remove();
 }
Nach dem Login kopieren

Wenn Sie sich die Iterator-Schnittstellen-API ansehen, können Sie es wissen dass dies ein Iterator zum Durchlaufen der Sammlung ist. Iteratoren ermöglichen es dem Aufrufer, mithilfe einer genau definierten Semantik Elemente aus der Sammlung zu entfernen, auf die der Iterator während der Iteration zeigt.

Besonders hervorzuheben ist die Verwendung der Methode „remove()“ dieses Iterators: Entfernen des letzten vom Iterator zurückgegebenen Elements (optionale Operation) aus der Sammlung, auf die der Iterator zeigt. Diese Methode kann nur einmal pro Aufruf von next aufgerufen werden. Wenn die Sammlung, auf die der Iterator zeigt, während einer Iteration anders als durch den Aufruf dieser Methode (Remove-Methode) geändert wird, ist das Verhalten des Iterators undefiniert. Der Schnittstellendesigner hat beim Entwerfen der Iterator-Schnittstelle darauf hingewiesen, dass der Aufruf einer anderen Methode „remove()“ als des Iterators zum Ändern der Sammlung, auf die der Iterator während der Iteration zeigt, ungewisse Konsequenzen hat. Die spezifischen Konsequenzen hängen von der spezifischen Implementierung des Iterators ab. Als Reaktion auf die möglichen Situationen, in denen solche ungewissen Konsequenzen auftreten können, bin ich beim Erlernen von ArrayList auf eine davon gestoßen: Der Iterator hat eine ConcurrentModificationException-Ausnahme ausgelöst. Die spezifische Ausnahmesituation wird im folgenden Code dargestellt:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
 
public class ItaratorTest {
 
  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");
 
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String lang = iterator.next();
      list.remove(lang);//will throw ConcurrentModificationException
    }
  }
 
}
Nach dem Login kopieren

Dieser Code löst beim Ausführen eine ConcurrentModificationException-Ausnahme aus, da wir während des Iterators keine Verwendung haben Führen Sie die Methode „remove()“ von Iterator aus, um Elemente zu löschen, verwenden Sie jedoch die Methode „remove()“ von ArrayList, um die Sammlung zu ändern, auf die der Iterator zeigt. Dies verstößt gegen die Designprinzipien von Iteratoren, sodass eine Ausnahme auftritt.

Die gemeldete Ausnahme lautet wie folgt:

Ausnahme im Thread „main“ java.util.ConcurrentModificationException
bei java.util.ArrayList$Itr.checkForComodification ( ArrayList.java:859)
bei java.util.ArrayList$Itr.next(ArrayList.java:831)
bei Text.ItaratorTest.main(ItaratorTest.java:17)

2. for-each-Schleife und Iterator Iterator

Ab Java5 gibt es in Java eine for-each-Schleife, mit der Sammlungen und Arrays durchlaufen werden können. Mit der Foreach-Schleife können Sie die Sammlung durchlaufen, ohne den Index in einer herkömmlichen for-Schleife verwalten zu müssen oder ohne die hasNext()-Methode in der while-Schleife aufzurufen, wenn Sie iterator / ListIterator (eine Iteratorimplementierung in ArrayList) verwenden. Die for-each-Schleife vereinfacht das Durchlaufen einer Sammlung oder eines Arrays. Bei der Verwendung einer foreach-Schleife sind jedoch zwei Punkte zu beachten.

Objekte, die eine foreach-Schleife verwenden, müssen die Iterable-Schnittstelle implementieren

Bitte sehen Sie sich das folgende Beispiel an:

import java.util.ArrayList;
 
public class ForeachTest1 {
 
  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");
 
    // What does this code will do, print language, throw exception or
    // compile time error
    for (String language : myCollection) {
      System.out.println(language);
    }
  }
 
  private class CustomCollection<T> {
    private ArrayList<T> bucket;
 
    public CustomCollection() {
      bucket = new ArrayList();
    }
 
    public int size() {
      return bucket.size();
    }
 
    public boolean isEmpty() {
      return bucket.isEmpty();
    }
 
    public boolean contains(T o) {
      return bucket.contains(o);
    }
 
    public boolean add(T e) {
      return bucket.add(e);
    }
 
    public boolean remove(T o) {
      return bucket.remove(o);
    }
 
  }
}
Nach dem Login kopieren

Der obige Code wird nicht kompiliert, da die CustomCollection-Klasse im Code die Iterable-Schnittstelle nicht implementiert. Der beim Kompilieren gemeldete Fehler ist wie folgt:

Ausnahme im Thread „. main" java .lang.Error: Ungelöstes Kompilierungsproblem:
Kann nur über ein Array oder eine Instanz von java.lang.Iterable

bei Text.ForeachTest1.main(ForeachTest1.java:15)< iterieren 🎜>

Tatsächlich muss man nicht bis zur Kompilierung warten, um den Fehler zu finden. Nach dem Schreiben dieses Codes zeigt Eclipse den Fehler in der foreach-Schleife an: Kann nur über ein Array oder eine Java-Instanz iterieren. lang.Iterable

Was aus dem obigen Beispiel noch einmal bestätigt werden kann, ist, dass die foreach-Schleife nur für Objekte gilt, die die Iterable-Schnittstelle implementieren. Da alle integrierten Collection-Klassen die java.util.Collection-Schnittstelle implementieren und Iterable geerbt haben, können Sie zur Lösung der oben genannten Probleme wählen, ob CustomCollection einfach die Collection-Schnittstelle implementieren oder AbstractCollection erben soll. Die Lösung lautet wie folgt:

import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Iterator;
 
public class ForeachTest {
  public static void main(String args[]) {
    CustomCollection<String> myCollection = new CustomCollection<String>();
    myCollection.add("Java");
    myCollection.add("Scala");
    myCollection.add("Groovy");
    for (String language : myCollection) {
      System.out.println(language);
    }
  }
 
  private static class CustomCollection<T> extends AbstractCollection<T> {
    private ArrayList<T> bucket;
 
    public CustomCollection() {
      bucket = new ArrayList();
    }
 
    public int size() {
      return bucket.size();
    }
 
    public boolean isEmpty() {
      return bucket.isEmpty();
    }
 
    public boolean contains(Object o) {
      return bucket.contains(o);
    }
 
    public boolean add(T e) {
      return bucket.add(e);
    }
 
    public boolean remove(Object o) {
      return bucket.remove(o);
    }
 
    @Override
    public Iterator<T> iterator() {
      // TODO Auto-generated method stub
      return bucket.iterator();
    }
  }
}
Nach dem Login kopieren

2. Die interne Implementierung der foreach-Schleife basiert ebenfalls auf Iterator

Um zu überprüfen, ob die foreach-Schleife Iterator verwendet Als interne Implementierung verwenden wir tatsächlich immer noch das Beispiel am Anfang dieses Artikels zur Überprüfung:

public class ItaratorTest {
 
  public static void main(String[] args) {
    Collection<String> list = new ArrayList<String>();
    list.add("Android");
    list.add("IOS");
    list.add("Windows Mobile");
 
    // example1
    // Iterator<String> iterator = list.iterator();
    // while (iterator.hasNext()) {
    // String lang = iterator.next();
    // list.remove(lang);
    // }
 
    // example 2
    for (String language : list) {
      list.remove(language);
    }
  }
 
}
Nach dem Login kopieren

Ausnahme gemeldet, wenn das Programm ausgeführt wird:


Ausnahme im Thread „main“ java.util.ConcurrentModificationException

bei java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
bei java.util.ArrayList$Itr.next( ArrayList.java:831)
bei Text .ItaratorTest.main(ItaratorTest.java:22)

Diese Ausnahme zeigt, dass der Iterator innerhalb der for-each-Schleife verwendet wird, um die Sammlung zu durchlaufen Ruft außerdem Iterator.next() auf, das Änderungen (des Elements) überprüft und eine ConcurrentModificationException auslöst.

Zusammenfassung:

Wenn Sie beim Durchlaufen einer Sammlung die Sammlung während des Durchlaufens ändern möchten, müssen Sie dies über Iterator/listIterator tun, da sonst „unbestimmte Konsequenzen“ auftreten können.


Die foreach-Schleife wird durch einen Iterator implementiert. Das Objekt, das die foreach-Schleife verwendet, muss die Iterable-Schnittstelle implementieren


Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er zum Lernen aller beiträgt. Ich hoffe auch, dass jeder die PHP-Chinesisch-Website unterstützt.

Ausführlichere Artikel zu for-each-Schleifen und Iterationen in JAVA finden Sie auf der chinesischen PHP-Website!


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage