Ich wurde in einem Interview gefragt, was der Vorteil der Verwendung des Iterators mit der for-Schleife ist oder was der Vorteil der Verwendung des for-Loops gegenüber dem Iterator ist.
Kann irgendjemand dies bitte beantworten, damit ich es in Zukunft beantworten kann, wenn ich vor ähnlichen Fragen stehe?
Iterator
?Antworten:
Zunächst gibt es zwei Arten von for-Schleifen, die sich sehr unterschiedlich verhalten. Man verwendet Indizes:
for (int i = 0; i < list.size(); i++) { Thing t = list.get(i); ... }
Diese Art von Schleife ist nicht immer möglich. Listen haben beispielsweise Indizes, Sets jedoch nicht, da es sich um ungeordnete Sammlungen handelt.
Die andere, die foreach-Schleife, verwendet einen Iterator hinter den Kulissen:
for (Thing thing : list) { ... }
Dies funktioniert mit jeder Art von Iterable-Sammlung (oder Array)
Und schließlich können Sie einen Iterator verwenden, der auch mit jedem Iterable funktioniert:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) { Thing t = it.next(); ... }
Sie haben also tatsächlich 3 Schleifen zum Vergleichen.
Sie können sie in verschiedenen Begriffen vergleichen: Leistung, Lesbarkeit, Fehleranfälligkeit, Fähigkeit.
Ein Iterator kann Dinge tun, die eine foreach-Schleife nicht kann. Beispielsweise können Sie Elemente während der Iteration entfernen, wenn der Iterator dies unterstützt:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) { Thing t = it.next(); if (shouldBeDeleted(thing) { it.remove(); } }
Listen bieten auch Iteratoren, die in beide Richtungen iterieren können. Eine foreach-Schleife iteriert nur vom Anfang bis zum Ende.
Ein Iterator ist jedoch gefährlicher und weniger lesbar. Wenn Sie nur eine foreach-Schleife benötigen, ist dies die am besten lesbare Lösung. Mit einem Iterator könnten Sie Folgendes tun, was ein Fehler wäre:
for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) { System.out.println(it.next().getFoo()); System.out.println(it.next().getBar()); }
Eine foreach-Schleife lässt einen solchen Fehler nicht zu.
Die Verwendung von Indizes für den Zugriff auf Elemente ist bei Sammlungen, die von einem Array unterstützt werden, etwas effizienter. Wenn Sie jedoch Ihre Meinung ändern und eine LinkedList anstelle einer ArrayList verwenden, ist die Leistung plötzlich schrecklich, da
list.get(i)
die verknüpfte Liste bei jedem Zugriff alle ihre Elemente bis zur i-ten durchlaufen muss. Ein Iterator (und damit die foreach-Schleife) hat dieses Problem nicht. Es wird immer die bestmögliche Methode zum Durchlaufen von Elementen der angegebenen Sammlung verwendet, da die Sammlung selbst über eine eigene Iterator-Implementierung verfügt.Meine allgemeine Faustregel lautet: Verwenden Sie die foreach-Schleife, es sei denn, Sie benötigen wirklich die Funktionen eines Iterators. Ich würde for-Schleife nur mit Indizes mit Arrays verwenden, wenn ich Zugriff auf den Index innerhalb der Schleife benötige.
quelle
Iterator Vorteil:
next()
und vorwärts und rückwärts zu bewegenprevious()
.hasNext()
.Die Schleife wurde nur für die Iteration über a
Collection
entwickelt. Wenn Sie also nur über eine Iteration iterieren möchtenCollection
, ist es besser, eine Schleife wie zu verwendenfor-Each
, aber wenn Sie mehr wollen, als Sie Iterator verwenden können.quelle
ListIterator
Sie auchadd
die Iteration an einem beliebigen Punkt starten.Wenn Sie über eine Nummer (z. B. "i") auf Daten zugreifen, ist dies bei Verwendung des Arrays schnell. weil es direkt zum Element geht
Bei anderen Datenstrukturen (z. B. Baum, Liste) benötigt es jedoch mehr Zeit, da es vom ersten Element zum Zielelement beginnt. wenn Sie Liste verwenden. Es braucht Zeit O (n). es soll also langsam sein.
Wenn Sie den Iterator verwenden, weiß der Compiler, wo Sie sich befinden. es braucht also O (1) (weil es von der aktuellen Position ausgeht)
Schließlich, wenn Sie nur Array- oder Datenstrukturen verwenden, die direkten Zugriff unterstützen (z. B. Arraylist bei Java). "a [i]" ist gut. Wenn Sie jedoch eine andere Datenstruktur verwenden, ist der Iterator effizienter
quelle
Collections
. Es ist erwähnenswert, dass eine verbesserte for-Schleife eineIterator
unter der Haube verwendet.Der Hauptunterschied zwischen Iterator und der klassischen for-Schleife besteht neben dem offensichtlichen Unterschied, dass ich Zugriff auf den Index des zu iterierenden Elements habe oder nicht, darin, dass die Verwendung von Iterator den Clientcode von der zugrunde liegenden Auflistungsimplementierung abstrahiert erarbeiten.
Wenn Ihr Code einen Iterator verwendet, entweder in dieser Form
for(Item element : myCollection) { ... }
diese Form
Iterator<Item> iterator = myCollection.iterator(); while(iterator.hasNext()) { Item element = iterator.next(); ... }
oder diese Form
for(Iterator iterator = myCollection.iterator(); iterator.hasNext(); ) { Item element = iterator.next(); ... }
In Ihrem Code heißt es: "Die Art der Sammlung und ihre Implementierung sind mir egal, ich kümmere mich nur darum, dass ich ihre Elemente durchlaufen kann." Dies ist normalerweise der bessere Ansatz, da dadurch Ihr Code entkoppelt wird.
Auf der anderen Seite, wenn Sie die klassische for-Schleife wie in verwenden
for(int i = 0; i < myCollection.size(); i++) { Item element = myCollection.get(i); ... }
Ihr Code sagt, ich muss die Art der Sammlung kennen, da ich ihre Elemente auf eine bestimmte Weise durchlaufen muss. Möglicherweise werde ich auch nach Nullen suchen oder ein Ergebnis basierend auf der Reihenfolge der Iteration berechnen. Dies macht Ihren Code anfälliger, da sich die Art der Sammlung, die Sie erhalten, zu irgendeinem Zeitpunkt auf die Funktionsweise Ihres Codes auswirkt.
Zusammenfassend lässt sich sagen, dass der Unterschied nicht so sehr in der Geschwindigkeit oder der Speichernutzung liegt, sondern vielmehr in der Entkopplung Ihres Codes, damit Sie flexibler mit Änderungen umgehen können.
quelle
Im Gegensatz zu anderen Antworten möchte ich auf andere Dinge hinweisen;
Wenn Sie die Iteration an mehr als einer Stelle in Ihrem Code ausführen müssen, wird die Logik wahrscheinlich dupliziert. Dies ist eindeutig kein sehr erweiterbarer Ansatz. Stattdessen ist eine Möglichkeit erforderlich, die Logik für die Auswahl der Daten aus dem Code zu trennen, der sie tatsächlich verarbeitet.
Ein Iterator löst diese Probleme, indem er eine generische Schnittstelle zum Durchlaufen eines Datensatzes bereitstellt, sodass die zugrunde liegende Datenstruktur oder der zugrunde liegende Speichermechanismus - beispielsweise ein Array - ausgeblendet wird.
CopyOnWriteArrayList
aber er ist bekannt und wird oft so erwähnenswert verwendet.Dies ist aus dem Buch, dass es https://www.amazon.com/Beginning-Algorithms-Simon-Harris/dp/0764596748 ist
quelle
Ich bin über diese Frage gestolpert. Die Antwort liegt auf den Problemen, die Iterator zu lösen versucht:
quelle