Como evitar “ConcurrentModificationException” ao remover elementos de “ArrayList” ao iterá-lo?

Eu estou tentando remover alguns elementos de um ArrayList enquanto iterar isso assim:

 for (String str : myArrayList) { if (someCondition) { myArrayList.remove(str); } } 

Obviamente, recebo um ConcurrentModificationException ao tentar remover itens da lista ao mesmo tempo em que iterating myArrayList . Existe alguma solução simples para resolver este problema?

Use um Iterator e chame remove() :

 Iterator iter = myArrayList.iterator(); while (iter.hasNext()) { String str = iter.next(); if (someCondition) iter.remove(); } 

Como alternativa às respostas de todos os outros, sempre fiz algo assim:

 List toRemove = new ArrayList(); for (String str : myArrayList) { if (someCondition) { toRemove.add(str); } } myArrayList.removeAll(toRemove); 

Isso evitará que você tenha que lidar diretamente com o iterador, mas requer outra lista. Eu sempre preferi essa rota por qualquer motivo.

O usuário do Java 8 pode fazer isso: list.removeIf(...)

  List list = new ArrayList<>(Arrays.asList("a", "b", "c")); list.removeIf(e -> (someCondition)); 

Ele irá remover elementos na lista, para os quais someCondition está satisfeito

Você precisa usar o método remove () do iterador, o que significa que não há loop aprimorado:

 for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) { iterator.next(); if (someCondition) { iterator.remove(); } } 

Não não não!

Em tarefas simples, você não precisa usar o Iterator, além disso, CopyOnWriteArrayList (devido ao desempenho).

A solução é muito mais simples: tente usar o loop canônico em vez do loop for-each .

De acordo com os proprietários de direitos autorais Java (alguns anos atrás, Sun, agora Oracle) para cada guia de loop , ele usa o iterador para percorrer a coleção e apenas a oculta para tornar o código mais atraente. Mas, infelizmente, como podemos ver, produziu mais problemas do que lucros, caso contrário, este tópico não surgiria.

Por exemplo, esse código levará a java.util.ConcurrentModificationException ao inserir a próxima iteração na ArrayList modificada:

  // process collection for (SomeClass currElement: testList) { SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); } } 

Mas seguir código funciona muito bem:

  // process collection for (int i = 0; i < testList.size(); i++) { SomeClass currElement = testList.get(i); SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); i--; //to avoid skipping of shifted element } } 

Portanto, tente usar a abordagem de indexação para iterar sobre collections e evitar o loop for-each, pois elas não são equivalentes! For-each loop usa alguns iteradores internos, que verificam a modificação da coleção e lançam a exceção ConcurrentModificationException. Para confirmar isso, observe mais de perto o rastreio da pilha impressa ao usar o primeiro exemplo que postei:

 Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) at java.util.AbstractList$Itr.next(AbstractList.java:343) at TestFail.main(TestFail.java:43) 

Para multithreading, use abordagens multitarefas correspondentes (como palavra-chave sincronizada).

Enquanto outras soluções sugeridas funcionam, se você realmente quer que a solução seja feita com segurança, você deve replace ArrayList por CopyOnWriteArrayList.

  //List s = new ArrayList<>(); //Will throw exception List s = new CopyOnWriteArrayList<>(); s.add("B"); Iterator it = s.iterator(); s.add("A"); //Below removes only "B" from List while (it.hasNext()) { s.remove(it.next()); } System.out.println(s); 

Um método alternativo é converter sua List em array , iterá-los e removê-los diretamente da List base em sua lógica.

 List myList = new ArrayList(); // You can use either list or set myList.add("abc"); myList.add("abcd"); myList.add("abcde"); myList.add("abcdef"); myList.add("abcdefg"); Object[] obj = myList.toArray(); for(Object o:obj) { if(condition) myList.remove(o.toString()); } 

Se você quiser modificar sua Lista durante a travessia, então você precisa usar o Iterator . E então você pode usar iterator.remove() para remover os elementos durante a travessia.

 List myArrayList = Collections.synchronizedList(new ArrayList()); //add your elements myArrayList.add(); myArrayList.add(); myArrayList.add(); synchronized(myArrayList) { Iterator i = myArrayList.iterator(); while (i.hasNext()){ Object object = i.next(); } } 

Você pode usar a function iterator remove () para remover o object do object de coleção subjacente. Mas neste caso você pode remover o mesmo object e não qualquer outro object da lista.

daqui