Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop

We all know you can't do the following because of ConcurrentModificationException:

for (Object i : l) {     if (condition(i)) {         l.remove(i);     } } 

But this apparently works sometimes, but not always. Here's some specific code:

public static void main(String[] args) {     Collection<Integer> l = new ArrayList<>();      for (int i = 0; i < 10; ++i) {         l.add(4);         l.add(5);         l.add(6);     }      for (int i : l) {         if (i == 5) {             l.remove(i);         }     }      System.out.println(l); } 

This, of course, results in:

Exception in thread "main" java.util.ConcurrentModificationException 

Even though multiple threads aren't doing it. Anyway.

What's the best solution to this problem? How can I remove an item from the collection in a loop without throwing this exception?

I'm also using an arbitrary Collection here, not necessarily an ArrayList, so you can't rely on get.

like image 783
Claudiu Avatar asked Oct 21 '08 23:10

Claudiu


People also ask

How will you efficiently remove elements while iterating a Collection?

The right way to remove objects from ArrayList while iterating over it is by using the Iterator's remove() method.

Why does iterator remove Do not throw ConcurrentModificationException?

Notice that iterator. remove() doesn't throw an exception by itself because it is able to update both the internal state of itself and the collection. Calling remove() on two iterators of the same instance collection would throw, however, because it would leave one of the iterators in an inconsistent state.

What is ConcurrentModificationException what will happen if we use remove?

ConcurrentModificationException is a very common exception when working with Java collection classes. Java Collection classes are fail-fast, which means if the Collection will be changed while some thread is traversing over it using iterator, the iterator. next() will throw ConcurrentModificationException.


1 Answers

Iterator.remove() is safe, you can use it like this:

List<String> list = new ArrayList<>();  // This is a clever way to create the iterator and call iterator.hasNext() like // you would do in a while-loop. It would be the same as doing: //     Iterator<String> iterator = list.iterator(); //     while (iterator.hasNext()) { for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {     String string = iterator.next();     if (string.isEmpty()) {         // Remove the current element from the iterator and the list.         iterator.remove();     } } 

Note that Iterator.remove() is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.

Source: docs.oracle > The Collection Interface


And similarly, if you have a ListIterator and want to add items, you can use ListIterator#add, for the same reason you can use Iterator#remove — it's designed to allow it.


In your case you tried to remove from a list, but the same restriction applies if trying to put into a Map while iterating its content.

like image 89
Bill K Avatar answered Oct 06 '22 04:10

Bill K