How to iterate through a Collection, avoiding ConcurrentModificationException when removing objects in a loop? [Answered]

Sample problem:

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.

Answer #1:

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.

Answer #2:

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.

Answer #3:

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);

Answer #4:

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.

Answer #5:

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);
}

Answer #6:

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.

Answer #7:

With a for loop:

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

Answer #8:

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

for (String str : new ArrayList<String>(listOfStr))     
{
    listOfStr.remove(/* object reference or index */);
}

Answer #9:

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.

Answer #10:

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.

Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop- Answer #11:

With a traditional for loop

ArrayList<String> myArray = new ArrayList<>();

for (int i = 0; i < myArray.size(); ) {
    String text = myArray.get(i);
    if (someCondition(text))
        myArray.remove(i);
    else
        i++;   
}

Hope you learned something from this post.

Follow Programming Articles for more!

About ᴾᴿᴼᵍʳᵃᵐᵐᵉʳ

Linux and Python enthusiast, in love with open source since 2014, Writer at programming-articles.com, India.

View all posts by ᴾᴿᴼᵍʳᵃᵐᵐᵉʳ →