0

The following code does not throw ConcurrentModificationException

    public static void main(String[] args)
    {
        List<String> l1 = new ArrayList<>();
        l1.add("v1");
        Iterator<String> it =  l1.iterator();
        l1.remove(0);
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }

Whereas this code throws ConcurrentModificationException

    public static void main(String[] args)
    {
        List<String> l1 = new ArrayList<>();
        l1.add("v1");
        Iterator<String> it =  l1.iterator();
        l1.add("v2");
        while(it.hasNext()) {
            System.out.println(it.next());
        }
    }

Both operations are structural modifications of list, but why exception is thrown only in case of addition?

  • 2
    When you remove the element the list is empty and the `Iterator` returned by `ArrayList` only checks the modification count when you call `next()`, not `hasNext()`. Maybe a bug? – Slaw Aug 19 '19 at 20:18
  • yes i think you are right. if i add 2 elements, get the iterator and then remove one element and iterate, it throws the exception – Manohar Bhat Aug 19 '19 at 20:21
  • related: https://stackoverflow.com/q/57168307/85421 (and others that is duplicate from) - `hasNext()` does not throw that Exception, if `next()` is not called, no Exception will be thrown – user85421 Aug 19 '19 at 20:34
  • Javadoc of [Iterator](https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Iterator.html): "Therefore, it would be wrong to write a program that depended on this exception for its correctness: *the fail-fast behavior of iterators should be used only to detect bugs*." – user85421 Aug 19 '19 at 20:47

1 Answers1

0

Look at ArrayList.Itr.

There're two counters: ArrayList.modCount and ArrayList.Itr.expectedModCount. ArrayList.Itr throws ConcurrentModificationException when modCount != expectedModCount.

This is correct. But if you look at ArrayList.Itr.hasNext you can see:

public boolean hasNext() {
    return cursor != size;
}

When you remove one element and you list become empty, then your code does not invoke it.next().

To make your code throw ConcurrentModificationException, you should have not empty list before while loop:

public static void main(String[] args)
{
    List<String> l1 = new ArrayList<>();
    l1.add("v1");
    l1.add("v2");
    Iterator<String> it =  l1.iterator();
    l1.remove(0);
    while(it.hasNext()) {
        System.out.println(it.next());  // --> ConcurrentModificationException
    }
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35