Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why iterator.remove does not throw ConcurrentModificationException

Tags:

What does iterator.remove() do differently from list.remove(), so that iterator does not throw an exception and list.remove() does throw one? In the end, both are modifying the collection size.

Please ignore multi-threading here. I am just talking about a for-each loop and an iterator loop. As far as I know, a for-each loop creates an iterator only internally.

I am confused.

like image 420
javafan Avatar asked Jul 21 '14 02:07

javafan


People also ask

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.

Which method of the iterator throws ConcurrentModificationException?

Iterator implementations that throw ConcurrentModificationException are known as fail-fast iterators, as they fail quickly and cleanly, rather than risking arbitrary, non-deterministic behavior later.


1 Answers

I think you mean, if you're iterating a list, why does list.remove() cause a ConcurrentModificationException to be thrown whereas iterator.remove() does not?

Consider this example:

    List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));

    for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
        if (iter.next().equals("b")) {
            // iter.remove();    // #1
            // list.remove("b"); // #2
        }
    }

If you uncomment line #1, it will work fine. If you uncomment line #2 (but leave #1 commented) then it will cause the subsequent call to iter.next() to throw ConcurrentModificationException.

The reason is that the iterator is a separate object that has some references to the internal state of the underlying list. If you modify the list while the iterator is in operation, it could cause the iterator to behave badly, e.g. by skipping elements, repeating elements, indexing off the end of the array, etc. It attempts to detect such modifications and so it throws ConcurrentModificationException if it does.

Removing elements through the iterator works and does not cause exceptions, because this updates the underlying list and the iterator's state that refers to the internals of the list, so everything can stay consistent.

However, there is nothing special about iterator.remove() that makes it work in all cases. If there are multiple iterators iterating over the same list, modifications made by one will cause problems for the others. Consider:

    Iterator<String> i1 = list.iterator();
    Iterator<String> i2 = list.iterator();
    i1.remove();
    i2.remove();

We now have two iterators pointing into the same list. If we modify the list using one of them, it disrupts the operation of the second, so the call to i2.remove() will result in ConcurrentModificationException.

like image 145
Stuart Marks Avatar answered Sep 18 '22 18:09

Stuart Marks