Uwaga: znam Iterator#remove()
metodę.
W poniższym przykładzie kodu nie rozumiem, dlaczego metoda List.remove
in main
zgłasza ConcurrentModificationException
, ale nie w remove
metodzie.
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
źródło
źródło
Iterator#remove()
. Dlaczego robisz to w ten sposób?ConcurrentModificationException
a druga nie.return;
do pętli.Odpowiedzi:
Oto dlaczego: Jak jest napisane w Javadoc:
To sprawdzenie odbywa się w
next()
metodzie iteratora (jak widać po ścieżce stosu). Ale dotrzemy donext()
metody tylko wtedy, gdy zostaniehasNext()
dostarczona jako prawda, czyli to, co jest wywoływane przez for each, aby sprawdzić, czy granica jest spełniona. W twojej metodzie remove, gdyhasNext()
sprawdza, czy musi zwrócić inny element, zobaczy, że zwróciła dwa elementy, a teraz po usunięciu jednego elementu lista zawiera tylko dwa elementy. Wszystko jest więc brzoskwiniowe i skończyliśmy z iteracją. Sprawdzanie współbieżnych modyfikacji nie występuje, ponieważ jest to wykonywane wnext()
metodzie, która nigdy nie jest wywoływana.Następnie przechodzimy do drugiej pętli. Po usunięciu drugiej liczby metoda hasNext ponownie sprawdzi, czy może zwrócić więcej wartości. Zwrócił już dwie wartości, ale lista zawiera teraz tylko jedną. Ale kod tutaj to:
1! = 2, więc kontynuujemy do
next()
metody, która teraz zdaje sobie sprawę, że ktoś majstrował przy liście i uruchamia wyjątek.Mam nadzieję, że to wyjaśnia twoje pytanie.
Podsumowanie
List.remove()
nie wyrzuci,ConcurrentModificationException
gdy usunie przedostatni element z listy.źródło
Jednym ze sposobów radzenia sobie z tym jest usunięcie czegoś z kopii
Collection
(nie samej kolekcji), jeśli ma to zastosowanie.Clone
oryginalną kolekcję, aby wykonać kopię za pośrednictwem plikuConstructor
.W twoim konkretnym przypadku, po pierwsze, nie sądzę, aby
final
był to sposób na rozważenie, że zamierzasz zmodyfikować listę wcześniejszych deklaracjiRozważ także modyfikację kopii zamiast oryginalnej listy.
źródło
Metoda forward / iterator nie działa podczas usuwania elementów. Możesz usunąć element bez błędu, ale podczas próby uzyskania dostępu do usuniętych elementów wystąpi błąd w czasie wykonywania. Nie możesz użyć iteratora, ponieważ jak pokazuje pushy, spowoduje to ConcurrentModificationException, więc zamiast tego użyj zwykłej pętli for, ale przejdź przez nią wstecz.
Rozwiązanie:
Przechodź przez tablicę w odwrotnej kolejności, jeśli zamierzasz usunąć element listy. Po prostu przechodząc wstecz przez listę, unikasz odwiedzania usuniętego elementu, co usuwa wyjątek.
źródło
Ten fragment kodu zawsze spowoduje zgłoszenie wyjątku ConcurrentModificationException.
Reguła brzmi: „Nie możesz modyfikować (dodawać ani usuwać elementów z listy) podczas iteracji po niej za pomocą Iteratora (co ma miejsce, gdy używasz pętli for-each)”.
JavaDocs:
Iteratory zwracane przez iterator i metody listIterator tej klasy działają szybko: jeśli lista zostanie strukturalnie zmodyfikowana w dowolnym momencie po utworzeniu iteratora, w jakikolwiek sposób z wyjątkiem metod usuwania lub dodawania własnych iteratora, iterator zgłosi ConcurrentModificationException.
Dlatego jeśli chcesz zmodyfikować listę (lub ogólnie jakąkolwiek kolekcję), użyj iteratora, ponieważ wtedy jest on świadomy modyfikacji i dlatego będą one poprawnie obsługiwane.
Mam nadzieję że to pomoże.
źródło
Miałem ten sam problem, ale na wypadek, gdybym dodawał element en do iterowanej listy. Zrobiłem to w ten sposób
Teraz wszystko idzie dobrze, ponieważ nie tworzysz żadnego iteratora na swojej liście, tylko iterujesz po niej „ręcznie”. I stan
i < integerList.size()
nigdy Cię nie oszuka, ponieważ kiedy usuniesz / dodasz coś do rozmiaru listy, zmniejszaj / zwiększaj listę.Mam nadzieję, że to pomoże, dla mnie to było rozwiązanie.
źródło
Jeśli używasz kolekcji kopiowanych przy zapisie, to zadziała; jednak gdy używasz list.iterator (), zwrócony Iterator będzie zawsze odwoływał się do kolekcji elementów, tak jak to było, gdy (jak poniżej) wywołano list.iterator (), nawet jeśli inny wątek modyfikuje kolekcję. Wszelkie metody mutujące wywoływane w Iteratorze opartym na kopiowaniu przy zapisie lub w ListIteratorze (na przykład add, set lub remove) generują wyjątek UnsupportedOperationException.
źródło
Działa to dobrze na Javie 1.6
~% javac RemoveListElementDemo.java
~% java RemoveListElementDemo
~% cat RemoveListElementDemo.java
~%
źródło
W moim przypadku zrobiłem to tak:
źródło
Zmień Iterator
for each
nafor loop
rozwiązywać.Powód jest taki:
- odesłano dokumenty Java.
źródło
Sprawdź swój kod człowieku ...
W głównej metodzie próbujesz usunąć czwarty element, którego nie ma i stąd błąd. W metodzie remove () próbujesz usunąć trzeci element, który tam jest, a zatem nie ma błędu.
źródło
2
i3
nie są indeksami listy, ale elementami. Obie logiki usuwania sprawdzająequals
elementy listy, a nie indeks elementów. Ponadto, jeśli został indeks związane byłobyIndexOutOfBoundsException
nieConcurrentModificationException
.