Heim >类库下载 >java类库 >for-each-Schleife und Iteration in JAVA

for-each-Schleife und Iteration in JAVA

高洛峰
高洛峰Original
2016-10-19 09:59:151839Durchsuche

1. Iterator-Iterator

Schnittstelle: Iterator

public interface Iterator<E>{

 boolean hasNext();

 E next();

 void remove();
 }

Wenn Sie sich die Iterator-Schnittstellen-API ansehen, können Sie erkennen, dass es sich um einen Iterator zum Iterieren der Sammlung handelt. 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: Entfernt das letzte vom Iterator zurückgegebene Element (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 Ausnahme ist 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
        }
    }

}

Dieser Code löst bei der Ausführung eine ConcurrentModificationException-Ausnahme aus, da wir nicht die Methode „remove()“ des Iterators verwenden, um Elemente während der Ausführung des Iterators zu löschen, sondern Verwenden Sie 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:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:17)

2. for-each-Schleife und Iterator-Iterator

Ab Java5 gibt es in Java die every-Schleife kann zum Durchlaufen von Sammlungen und Arrays verwendet werden. Mit der Foreach-Schleife können Sie über die Sammlung iterieren, ohne den Index in einer herkömmlichen for-Schleife beizubehalten oder ohne die Methode hasNext() 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);
        }

    }
}

Der obige Code wird nicht kompiliert, da die CustomCollection-Klasse in Der Code implementiert die Iterable-Schnittstelle nicht und der während der Kompilierung gemeldete Fehler lautet wie folgt:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Can only iterate over an array or an instance of java.lang.Iterable

    at Text.ForeachTest1.main(ForeachTest1.java:15)

Tatsächlich muss nicht bis zur Kompilierung gewartet werden, um den Fehler zu finden. Eclipse wird dies tun Beim Schreiben dieses Codes wird in der foreach-Schleife ein Fehler angezeigt: Kann nur über ein Array oder eine Instanz von java.lang.Iterable iterieren

Aus dem obigen Beispiel kann noch einmal bestätigt werden, dass die foreach-Schleife nur für gilt das Iterable-Objekt. 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();
        }
    }
}

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

Um die Tatsache zu überprüfen, dass die foreach-Schleife Iterator als interne Implementierung verwendet , wir verwenden immer noch diesen Artikel Die erste Instanz 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);
        }
    }

}

Ausnahme gemeldet, wenn das Programm ausgeführt wird:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Text.ItaratorTest.main(ItaratorTest.java:22)

Diese Ausnahme zeigt, dass ein Iterator innerhalb des For- verwendet wird. Außerdem wird jede Schleife zum Durchlaufen der Sammlung aufgerufen, die nach Änderungen sucht 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


Stellungnahme:
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