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.

Add Comment
25 Answer(s)

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.

Add Comment

This works:

Iterator<Integer> iter = l.iterator(); while (iter.hasNext()) {     if (iter.next() == 5) {         iter.remove();     } } 

I assumed that since a foreach loop is syntactic sugar for iterating, using an iterator wouldn’t help… but it gives you this .remove() functionality.

Add Comment

With Java 8 you can use the new removeIf method. Applied to your example:

Collection<Integer> coll = new ArrayList<>(); //populate  coll.removeIf(i -> i == 5); 
Add Comment

Since the question has been already answered i.e. the best way is to use the remove method of the iterator object, I would go into the specifics of the place where the error "java.util.ConcurrentModificationException" is thrown.

Every collection class has a private class which implements the Iterator interface and provides methods like next(), remove() and hasNext().

The code for next looks something like this…

public E next() {     checkForComodification();     try {         E next = get(cursor);         lastRet = cursor++;         return next;     } catch(IndexOutOfBoundsException e) {         checkForComodification();         throw new NoSuchElementException();     } } 

Here the method checkForComodification is implemented as

final void checkForComodification() {     if (modCount != expectedModCount)         throw new ConcurrentModificationException(); } 

So, as you can see, if you explicitly try to remove an element from the collection. It results in modCount getting different from expectedModCount, resulting in the exception ConcurrentModificationException.

Answered on July 16, 2020.
Add Comment

You can either use the iterator directly like you mentioned, or else keep a second collection and add each item you want to remove to the new collection, then removeAll at the end. This allows you to keep using the type-safety of the for-each loop at the cost of increased memory use and cpu time (shouldn’t be a huge problem unless you have really, really big lists or a really old computer)

public static void main(String[] args) {     Collection<Integer> l = new ArrayList<Integer>();     Collection<Integer> itemsToRemove = new ArrayList<>();     for (int i=0; i < 10; i++) {         l.add(Integer.of(4));         l.add(Integer.of(5));         l.add(Integer.of(6));     }     for (Integer i : l)     {         if (i.intValue() == 5) {             itemsToRemove.add(i);         }     }      l.removeAll(itemsToRemove);     System.out.println(l); } 
Answered on July 16, 2020.
Add Comment

In such cases a common trick is (was?) to go backwards:

for(int i = l.size() - 1; i >= 0; i --) {   if (l.get(i) == 5) {     l.remove(i);   } } 

That said, I’m more than happy that you have better ways in Java 8, e.g. removeIf or filter on streams.

Add Comment

Same answer as Claudius with a for loop:

for (Iterator<Object> it = objects.iterator(); it.hasNext();) {     Object object = it.next();     if (test) {         it.remove();     } } 
Add Comment

With Eclipse Collections, the method removeIf defined on MutableCollection will work:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5); list.removeIf(Predicates.lessThan(3)); Assert.assertEquals(Lists.mutable.of(3, 4, 5), list); 

With Java 8 Lambda syntax this can be written as follows:

MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5); list.removeIf(Predicates.cast(integer -> integer < 3)); Assert.assertEquals(Lists.mutable.of(3, 4, 5), list); 

The call to Predicates.cast() is necessary here because a default removeIf method was added on the java.util.Collection interface in Java 8.

Note: I am a committer for Eclipse Collections.

Add Comment

Make a copy of existing list and iterate over new copy.

for (String str : new ArrayList<String>(listOfStr))      {     listOfStr.remove(/* object reference or index */); } 
Answered on July 16, 2020.
Add Comment

People are asserting one can’t remove from a Collection being iterated by a foreach loop. I just wanted to point out that is technically incorrect and describe exactly (I know the OP’s question is so advanced as to obviate knowing this) the code behind that assumption:

for (TouchableObj obj : untouchedSet) {  // <--- This is where ConcurrentModificationException strikes     if (obj.isTouched()) {         untouchedSet.remove(obj);         touchedSt.add(obj);         break;  // this is key to avoiding returning to the foreach     } } 

It isn’t that you can’t remove from the iterated Colletion rather that you can’t then continue iteration once you do. Hence the break in the code above.

Apologies if this answer is a somewhat specialist use-case and more suited to the original thread I arrived here from, that one is marked as a duplicate (despite this thread appearing more nuanced) of this and locked.

Answered on July 16, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.