Hinweis: Mir ist die Iterator#remove()
Methode bekannt.
Im folgenden Codebeispiel verstehe ich nicht, warum die List.remove
in- main
Methode ausgelöst wird ConcurrentModificationException
, aber nicht in der remove
Methode.
public class RemoveListElementDemo {
private static final List<Integer> integerList;
static {
integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
}
public static void remove(Integer toRemove) {
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
public static void main(String... args) {
remove(Integer.valueOf(2));
Integer toRemove = Integer.valueOf(3);
for(Integer integer : integerList) {
if(integer.equals(toRemove)) {
integerList.remove(integer);
}
}
}
}
java
list
concurrentmodification
foreach
Bhesh Gurung
quelle
quelle
Iterator#remove()
. Warum machst du das so?ConcurrentModificationException
und die andere nicht.return;
in die Schleife behoben .Antworten:
Hier ist der Grund: Wie es im Javadoc heißt:
Diese Überprüfung erfolgt in der
next()
Methode des Iterators (wie Sie am Stacktrace sehen können). Wir werden dienext()
Methode jedoch nur erreichen, wennhasNext()
sie true geliefert wird. Dies wird von jedem aufgerufen, um zu überprüfen, ob die Grenze erreicht ist.hasNext()
Wenn Sie in Ihrer Methode remove prüfen, ob ein anderes Element zurückgegeben werden muss, werden zwei Elemente zurückgegeben. Nachdem ein Element entfernt wurde, enthält die Liste nur noch zwei Elemente. Also ist alles pfirsichfarben und wir sind mit dem Iterieren fertig. Die Prüfung auf gleichzeitige Änderungen findet nicht statt, da dies in dernext()
Methode erfolgt, die niemals aufgerufen wird.Als nächstes kommen wir zur zweiten Schleife. Nachdem wir die zweite Zahl entfernt haben, prüft die hasNext-Methode erneut, ob weitere Werte zurückgegeben werden können. Es wurden bereits zwei Werte zurückgegeben, aber die Liste enthält nur noch einen. Aber der Code hier ist:
1! = 2, also fahren wir mit der
next()
Methode fort, die nun erkennt, dass jemand mit der Liste herumgespielt hat, und die Ausnahme auslöst.Hoffe das klärt deine Frage.
Zusammenfassung
List.remove()
wird nicht geworfen,ConcurrentModificationException
wenn das vorletzte Element aus der Liste entfernt wird.quelle
Eine Möglichkeit, damit umzugehen, besteht darin
Collection
, gegebenenfalls etwas aus einer Kopie einer (nicht der Sammlung selbst) zu entfernen .Clone
die ursprüngliche Sammlung es, um eine Kopie über eine zu machenConstructor
.Zunächst einmal denke ich, dass
final
es für Ihren speziellen Fall kein guter Weg ist, wenn Sie beabsichtigen, die Liste nach der Deklaration zu ändernZiehen Sie auch in Betracht, eine Kopie anstelle der ursprünglichen Liste zu ändern.
quelle
Die Forward / Iterator-Methode funktioniert beim Entfernen von Elementen nicht. Sie können das Element ohne Fehler entfernen, es wird jedoch ein Laufzeitfehler angezeigt, wenn Sie versuchen, auf entfernte Elemente zuzugreifen. Sie können den Iterator nicht verwenden, da er, wie aufdringlich zeigt, eine ConcurrentModificationException verursacht. Verwenden Sie stattdessen eine reguläre for-Schleife, aber gehen Sie rückwärts durch.
Eine Lösung:
Durchlaufen Sie das Array in umgekehrter Reihenfolge, wenn Sie ein Listenelement entfernen möchten. Wenn Sie die Liste einfach rückwärts durchgehen, vermeiden Sie den Besuch eines entfernten Elements, wodurch die Ausnahme beseitigt wird.
quelle
Dieses Snippet löst immer eine ConcurrentModificationException aus.
Die Regel lautet "Sie dürfen keine Elemente ändern (Elemente zur Liste hinzufügen oder daraus entfernen), während Sie mit einem Iterator darüber iterieren (was passiert, wenn Sie eine for-each-Schleife verwenden)".
JavaDocs:
Die von den Iterator- und ListIterator-Methoden dieser Klasse zurückgegebenen Iteratoren sind ausfallsicher: Wenn die Liste zu irgendeinem Zeitpunkt nach dem Erstellen des Iterators strukturell geändert wird, löst der Iterator eine ConcurrentModificationException aus, außer durch die eigenen Iterator-Methoden zum Entfernen oder Hinzufügen.
Wenn Sie also die Liste (oder eine Sammlung im Allgemeinen) ändern möchten, verwenden Sie den Iterator, da er die Änderungen kennt und diese daher ordnungsgemäß behandelt werden.
Hoffe das hilft.
quelle
Ich hatte das gleiche Problem, aber für den Fall, dass ich ein Element in die iterierte Liste einfügte. Ich habe es so gemacht
Jetzt geht alles in Ordnung, da Sie keinen Iterator über Ihre Liste erstellen, sondern "manuell" darüber iterieren. Und die Bedingung
i < integerList.size()
wird Sie niemals täuschen, denn wenn Sie etwas in die Listengröße des Listendekrements / -inkrements entfernen / hinzufügen.Hoffe es hilft, für mich war das eine Lösung.
quelle
Wenn Sie Copy-on-Write-Sammlungen verwenden, funktioniert dies. Wenn Sie jedoch list.iterator () verwenden, verweist der zurückgegebene Iterator immer auf die Auflistung von Elementen, wie sie war, als (wie unten) list.iterator () aufgerufen wurde, selbst wenn ein anderer Thread die Auflistung ändert. Alle Mutationsmethoden, die für einen Iterator oder ListIterator auf Copy-on-Write-Basis aufgerufen werden (z. B. Hinzufügen, Festlegen oder Entfernen), lösen eine UnsupportedOperationException aus.
quelle
Dies läuft gut unter Java 1.6
~% javac RemoveListElementDemo.java
~% java RemoveListElementDemo
~% cat RemoveListElementDemo.java
~%
quelle
In meinem Fall habe ich es so gemacht:
quelle
Ändern Sie Iterator
for each
infor loop
zu lösen.Und der Grund ist:
- Referenzierte Java-Dokumente.
quelle
Überprüfen Sie Ihren Code Mann ....
In der Hauptmethode versuchen Sie, das 4. Element, das nicht vorhanden ist, und damit den Fehler zu entfernen. Bei der Methode remove () versuchen Sie, das dritte Element zu entfernen, das vorhanden ist, und daher keinen Fehler.
quelle
2
und3
sind keine Indizes für die Liste, sondern Elemente. Beide Entfernungslogiken prüfen anhandequals
der Listenelemente, nicht anhand des Index der Elemente. Wenn es indexbezogen wäreIndexOutOfBoundsException
, wäre dies nicht der FallConcurrentModificationException
.