Ich weiß, dass die iterator.next (), wenn die Collection geändert wird, während ein Thread sie mit Iterator durchläuft, ein SimultaneousModificationException .
Aber es zeigt ein anderes Verhalten, abhängig von der Anzahl der Elemente in der Liste.
Ich habe ein Code-Snippet ausprobiert, in dem ich eine Liste in for-jeder Schleife durchlaufen habe und dazwischen ein traversal mit der Methode remove () der Liste ein Element aus der Liste entfernt habe.
Idealerweise sollte es eine ConcurrentModificationException in dieser Bedingung auslösen, ohne von der Anzahl der Elemente in der Liste abhängig zu sein. Dies trifft jedoch nicht zu, wenn die Anzahl der Elemente in der Liste zwei ist.
Fall 1: Anzahl der Elemente in der Liste - 1
%Vor%Ausgabe : Eins
Ausnahme im Thread "main" java.util.ConcurrentModificationException
Das war wie erwartet.
Fall 2: Anzahl der Elemente in der Liste - 2
%Vor%Ausgabe: Eins
Es wird keine Ausnahme ausgelöst ?????????
Fall 3: Anzahl der Elemente in der Liste - 3
%Vor%Ausgabe : Eins
Ausnahme im Thread "main" java.util.ConcurrentModificationException
Wieder wird eine Ausnahme ausgelöst, was ein ideales Verhalten ist.
Aber warum wird es ordnungsgemäß in case-2 ausgeführt, ohne dass eine ConcurrentModificationException ausgelöst wird.
Aus der Dokumentation (Hervorhebung von mir) :
Die Iteratoren, die von der Klasse
iterator
undlistIterator
zurückgegeben wurden Methoden sind fail-fast : wenn die Liste strukturell modifiziert ist Zeit, nachdem der Iterator erstellt wurde, in keiner Weise außer durch Iterator eigeneremove
oderadd
-Methoden, der Iterator wirft ein %Code%. So angesichts der gleichzeitigen Änderung, der Iterator schlägt schnell und sauber, anstatt riskieren willkürliches, nicht-deterministisches Verhalten zu einer unbestimmten Zeit in der Zukunft.Beachten Sie, dass das Fail-Fast-Verhalten eines Iterators nicht garantiert werden kann wie es im allgemeinen unmöglich ist, harte Garantien zu geben bei unsynchronisierter gleichzeitiger Änderung. Fail-schnell Iteratoren werfen
ConcurrentModificationException
auf Best-Effort Basis. Daher wäre es falsch, ein Programm zu schreiben, das davon abhing auf diese Ausnahme für ihre Richtigkeit: das Fail-Fast-Verhalten von Iteratoren sollten nur verwendet werden, um Bugs zu erkennen .
Die vorherigen Antworten zeigen Ihnen die relevanten Dokumente, die erklären, warum dies angemessen ist. Sie sind nicht garantiert , um diese Ausnahme zu erhalten.
Wenn Sie wirklich wissen wollen, warum Sie nicht mit nur zwei Elementen erhalten (oder wirklich, wenn Sie das vorletzte Element unabhängig von der Größe entfernen), können Sie nachsehen im Quellcode für ArrayList
.
Ihre Schleife:
%Vor%ist eigentlich:
%Vor% Intern in Arraylist gibt es ein int size
, das die aktuelle Anzahl der Elemente in ArrayList
darstellt. Es wird dekrementiert, wenn Sie remove()
aufrufen.
Innerhalb der Iterator
gibt es eine int cursor
, die den aktuellen Standort (Index) von Iterator
darstellt. Es wird erhöht, wenn Sie next()
hasNext()
in Iterator
prüft die aktuelle Cursorposition gegen die Größe.
In Ihrem Beispiel ist die Kette der Ereignisse wie folgt:
cursor
beginnt bei 0
, size
beginnt bei 2
next()
wird aufgerufen, cursor
wird auf 1
erhöht. remove()
wird aufgerufen, size
wird auf 1
dekrementiert
hasNext()
vergleicht cursor
mit size
, stellt fest, dass sie identisch sind, gibt false
zurück
Wenn Sie also das vorletzte Element in der Größe ArrayList
entfernen, während Sie es durchlaufen, erhalten Sie keine Ausnahme. (Beachten Sie auch, dass Sie nie das letzte Element in dieser Liste in der Schleife verarbeiten werden; Ihr Beispiel druckt daher nur One
aus diesem Grund).
Denken Sie jedoch daran - dies ist ein Implementierungsdetail und ist nicht garantiert. Die Dokumentation sagt Ihnen, dass Sie sich nicht darauf verlassen sollten, dass die Ausnahme ausgelöst (oder nicht ausgelöst) wird. ArrayList
könnte auf eine andere Weise neu geschrieben werden, wobei das oben Genannte nicht mehr gilt und die Ausnahme ausgelöst wird (und tatsächlich in einer anderen JVM, die möglicherweise schon der Fall ist).
Es scheint, wenn Sie das angegebene Element aus der Liste entfernen, die Liste nicht weiß, dass ihre Größe geändert wurde.
Versuchen Sie Folgendes:
Entfernt das letzte von zurückgegebene Element aus der zugrunde liegenden Sammlung der Iterator (optionale Operation). Diese Methode kann nur einmal aufgerufen werden per Anruf zum nächsten. Das Verhalten eines Iterators ist nicht spezifiziert, wenn der Die zugrunde liegende Sammlung wird während der Iteration geändert in anderer Weise als durch Aufruf dieser Methode.
Tags und Links java list collections iterator concurrentmodification