Beide Snippets sind auf verschiedene Arten unterbrochen!
Fall 1 (mit Collection<String> col
):
Da ein Collection
unindexed ist, ist die einzige Methode remove
seine Schnittstelle aussetzt Collection.remove(Object o)
, die das angegebene Objekt gleich entfernt. Doing col.remove(1);
zuerst ruft Integer.valueOf(1)
, um ein Integer
Objekt zu erhalten, dann fragt die Liste, um dieses Objekt zu entfernen. Da die Liste keine solchen Integer
Objekte enthält, wird nichts entfernt. Die Iteration wird normalerweise über die Liste fortgesetzt und abc
ausgedruckt.
Fall 2 (mit ArrayList<String> col
):
Wenn col
‚s kompiliert Zeittyp ArrayList
wird, ruft col.remove(1);
Aufruf statt das Verfahren ArrayList.remove(int index)
das Element an der angegebenen Position zu entfernen, wodurch b
entfernen.
Nun, warum ist nicht c
ausgedruckt? Um eine Sammlung mit der for (X : Y)
-Syntax zu durchlaufen, ruft sie hinter den Kulissen die Sammlung auf, um ein Objekt Iterator
zu erhalten. Für die Iterator
zurückgegeben von ArrayList
(und die meisten Sammlungen) ist es nicht sicher, strukturelle Änderungen an der Liste während der Iteration durchzuführen - es sei denn, Sie ändern es durch die Methoden der Iterator
selbst - weil die Iterator
wird verwirrt und den Überblick verlieren welches Element als nächstes zurückkommt. Dies kann dazu führen, dass Elemente mehrmals durchlaufen werden, Elemente übersprungen werden oder andere Fehler auftreten. Das passiert hier: Element c
ist in der Liste vorhanden, aber nie ausgedruckt, weil Sie die Iterator
verwechselt haben.
Wenn ein Iterator
erkennt, dass dieses Problem aufgetreten ist, wird es Sie warnen, indem Sie eine werfen. Die Überprüfung, die eine Iterator
für das Problem durchführt, ist jedoch auf Geschwindigkeit und nicht auf 100% Korrektheit optimiert, und das Problem wird nicht immer erkannt. Wenn Sie in Ihrem Code s.equals("b")
in s.equals("a")
oder s.equals("c")
ändern, wird die Ausnahme ausgelöst (obwohl dies von der jeweiligen Java-Version abhängig sein kann). Aus den ArrayList
documentation:
Die die zurück Iteratoren von dieser Klasse iterator
und listIterator
Methoden sind ausfall schnell: wenn die Liste strukturell jederzeit geändert, nachdem der Iterator erstellt wird, in irgendeiner Weise, außer durch den Iterator eigenen remove
oder add
Methoden, der Iterator wird ConcurrentModificationException
werfen. Angesichts der gleichzeitigen Modifikation versagt der Iterator daher schnell und sauber, anstatt willkürliches, nicht-deterministisches Verhalten zu einem unbestimmten Zeitpunkt in der Zukunft zu riskieren.
Beachten Sie, dass das Fail-Fast-Verhalten eines Iterators nicht garantiert werden kann, da es im Allgemeinen unmöglich ist, bei unsynchronisierten simultanen Modifikationen harte Garantien zu geben. Fail-schnelle Iteratoren werfen ConcurrentModificationException
auf Best-Effort-Basis.
Um Elemente während der Iteration zu entfernen, können Sie die for (X : Y)
-Stil der Schleife über eine explizite Iterator
in einen manuellen Schleife ändern müssen, seine remove
Methode:
for (Iterator<String> it = col.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("b"))
it.remove();
System.out.print(s);
}
Dies ist jetzt völlig sicher . Es wird alle Elemente genau einmal durchlaufen (Drucken abc
), während das Element b
entfernt wird.
Wenn Sie möchten, können Sie den gleichen Effekt ohne Iterator
erreichen eine int i
-Stil-Schleife, wenn Sie sorgfältig den Index nach jedem Umzug einstellen:
for (int i = 0; i < col.size(); i++) {
String s = col.get(i);
if (s.equals("b")) {
col.remove(i);
i--;
}
System.out.print(s);
}
Können Sie den Teil darüber, wie die 'Sammlungen hinzufügen .remove() 'Methode akzeptiert ein" int "wegen Autoboxing? –
@TamoghnaChowdhury sure – Eran
Eine weitere Sache ArrayList hinzufügen ist Fail-schnelle Sammlung, also wenn Sie ein Element aus der Liste während des Traversieren entfernen, dann verwenden Sie CopyOnWriteArrayList, da es fehlersicher ist – emkays