2013-06-06 18 views
17

Wiem, że jeśli spróbuję usunąć kolekcję z pętli za pomocą prostej pętli, otrzymam ten wyjątek: java.util.ConcurrentModificationException. Ale używam Iterator i nadal generuje mi ten wyjątek. Każdy pomysł, dlaczego i jak go rozwiązać?java.util.ConcurrentModificationException z iteratorem

HashSet<TableRecord> tableRecords = new HashSet<>(); 

... 

    for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext();) { 
     TableRecord record = iterator.next(); 
     if (record.getDependency() == null) { 
      for (Iterator<TableRecord> dependencyIt = tableRecords.iterator(); dependencyIt.hasNext();) { 
       TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception 
       if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { 
        iterator.remove(); 
       } 
      } 
     } 
    } 

Odpowiedz

27

Musisz użyć iterator.remove() zamiast tableRecords.remove()

Można usuwać pozycje na liście, w którym iteracyjne tylko w przypadku korzystania z metody Usuń z iteracyjnej.

EDIT:

Po utworzeniu iterator, zaczyna liczyć modyfikacji, które zostały zastosowane w kolekcji. Jeśli iterator wykryje, że niektóre modyfikacje zostały wprowadzone bez użycia tej metody (lub przy użyciu innego iteratora w tej samej kolekcji), nie może już zagwarantować, że nie przejdzie on dwukrotnie na tym samym elemencie lub pominie jeden, więc wyrzuca ten wyjątek

oznacza to, że trzeba zmienić swój kod tak, że tylko usunąć elementy poprzez iterator.remove (i tylko z jednym iterator)

LUB

zrobić listę elementów, które można usunąć, a następnie usunąć je po zakończeniu iteracji .

+0

Istnieją dwie zagnieżdżone iteratory więc będzie to prawdopodobnie nie rozwiąże problemu. – assylias

+2

Wciąż to samo. – user2219247

+0

@assylias To prawda, nie widziałem drugiego. Dodałem kilka wyjaśnień na temat tego wyjątku. –

0

Kontrakt dla iteratora HashSeta polega na tym, że nie można go usunąć z hashsetu poza tą metodą usuwania iteratora spcific. Z perspektywy dependencyIt usunąłeś element inny niż wywołując jego metodę remove, więc rzuca on ConcurrentModificationException.

Wygląda na to, że chcesz usunąć rekordy z haszyszu, gdy mają ten sam identyfikator rekordu. Czy nie byłoby łatwiej zastąpić metody rekordów equals i hashcode, aby zapewnić, że rekordy o tym samym id są takie same i mają ten sam kod skrótu? (jeśli to oczywiście ma sens)

0

Problem polega na tym, że masz jednocześnie dwa iteratory w zasięgu i "walczą" ze sobą nawzajem. Najprostszym sposobem rozwiązania tego problemu jest po prostu wyskoczyć z pętli wewnętrznej, jeśli znajdziesz meczu:

for (Iterator<TableRecord> iterator = tableRecords.iterator(); iterator.hasNext();) { 
    TableRecord record = iterator.next(); 
    if (record.getDependency() == null) { 
     for (Iterator<TableRecord> dependencyIt = tableRecords.iterator(); dependencyIt.hasNext();) { 
      TableRecord dependency = dependencyIt.next(); //Here is the line which throws this exception 
      if (dependency.getDependency() != null && dependency.getDependency().getId().equals(record.getId())) { 
       iterator.remove(); 
       break; // ADD THIS LINE 
      } 
     } 
    } 
} 

Java Iterator s przeznaczone są na „nie szybko”, gdy ich bazowy pojemnik ulega zmianie bez uprzedniego zmieniać za pomocą Iterator. Używasz zagnieżdżonych iteratorów, więc każda wydana dla nich operacja remove() spowoduje, że druga osoba rzuci Exception, jeśli nadal będzie używana. Z tego powodu, jeśli musisz wydać remove(), musisz zrobić to na "zewnętrznym" iteratorze (który robisz) i przerwać później używanie drugiego iteratora (co dodała instrukcja break).

1

Iterator fail-fast sprawdza właściwości dla wszelkich zmian w strukturze podstawowej kolekcji za każdym staramy się uzyskać następny element. Jeśli zostaną znalezione jakieś modyfikacje, generuje wyjątek ConcurrentModificationException. Wszystkie implementacje Iterator w klasach kolekcji są projektami odpornymi na awarie z wyjątkiem współbieżnych klas kolekcji takich jak ConcurrentHashMap i CopyOnWriteArrayList.

Źródło: Google

Będziesz lepiej zrozumieć na przykładzie napisane poniżej: -

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Iterator; 
import java.util.List; 

public class IteratorExp { 
    public static void main(String... q) { 
     //CASE - ONE 
     List<String> strList = new ArrayList<>(Arrays.asList("a", "b", "c")); 
     Iterator<String> itr = strList.iterator(); 
     /* 
     * strList.add("e"); strList.add("f"); strList.add("g"); 
     */ 
     while (itr.hasNext()) { 
      System.out.println(itr.next()); 
     } 
     /* 
     * Exception in thread "main" java.util.ConcurrentModificationException 
     * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at 
     * java.util.ArrayList$Itr.next(Unknown Source) at 
     * IteratorExp.main(IteratorExp.java:14) 
     */ 

     //CASE - TWO 
     List<Integer> intList = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0)); 
     Iterator<Integer> itrOne = intList.iterator(); 
     Iterator<Integer> itrTwo = intList.iterator(); 
     for (; itrOne.hasNext();) { 
      if (itrOne.next().equals(5)) { 
       itrOne.remove(); // #1 
       //intList.remove(itrOne.next()); // #2 
      } 
     } 
     for (; itrTwo.hasNext();) { 
      if (itrTwo.next().equals(5)) { 
       itrTwo.remove(); // #1 
       //intList.remove(itrTwo.next()); // #2 
      } 
     } 

     /* 
     * Exception in thread "main" java.util.ConcurrentModificationException 
     * at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at 
     * java.util.ArrayList$Itr.next(Unknown Source) at 
     * IteratorExp.main(IteratorExp.java:35) 
     */ 
    } 
} 
Powiązane problemy