6

Fast-Fail : meaning that if they detect that the collection has changed since iteration began, they throw the unchecked ConcurrentModificationException.

I have written a test example to demonsterate this:

    String hi = "Hi";
    list.add(hi);
    list.add("Buy");
    System.out.println("list before: " + list);
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        String string = iterator.next();
        list.add("Good");
    }

the output is:

list before: [Hi, Buy]
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at thread.CollectionTest.main(CollectionTest.java:19)

which is expected. However, when an element is removed, the exception is not thrown:

    List<String> list = new ArrayList<>();

    String hi = "Hi";
    list.add(hi);
    list.add("Buy");
    System.out.println("list before: " + list);
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
        String string = iterator.next();
        list.remove(hi);
    }

Output:

list before: [Hi, Buy]
list after: [Buy]

Why is that? both cases the list is modified.

SantiBailors
  • 1,596
  • 3
  • 21
  • 44
hamid
  • 2,033
  • 4
  • 22
  • 42
  • 1
    Try removing before `iterator.next()` or try with 3 entries ... – Fildor Oct 28 '15 at 12:26
  • ConcurrentModificationException will throw when you remove an element during iteration. In your case you call the next() and then you remove the object. – Thanigai Arasu Oct 28 '15 at 12:30
  • @Thanigaiarasu I though `hasNext()` would also cause exception – hamid Oct 28 '15 at 12:32
  • 1
    I am not 100% sure, therefore only comment. You call `next` then remove, then hasNext checks whether the next `next` call would return an element. It would not, so it returns false. And the next `next` call is not executed that would finally throw the exception. That would be my explanation, though as I said, not 100% sure. So if you had 3 elements, hasNext would return true and the following next would throw. – Fildor Oct 28 '15 at 12:32
  • But to be honest, I'd have to try it out to verify my statement, too. – Fildor Oct 28 '15 at 12:35
  • 1
    @sam , In ArrayList `next()` method will look `checkForComodification`. If the `if (modCount != expectedModCount)` then will throw.ConcurrentModificationException – Thanigai Arasu Oct 28 '15 at 12:37
  • @Fildor you are absolutely right, just tried it and it is exactly as you explained it. – hamid Oct 28 '15 at 13:08
  • Second case will throw ConcurrentModificationException if the list has more than 2 elements. – LHA Oct 28 '15 at 13:32
  • 1
    This is probably a duplicate of http://stackoverflow.com/questions/14673653/why-isnt-this-code-causing-a-concurrentmodificationexception and others, but I'm always hesitant to use the dupehammer... :-/ – Marco13 Oct 28 '15 at 14:04

2 Answers2

1

The point is that it is not hasNext() that checks for modification, but next(). In your "remove" scenario, you suppress the next call that would throw because there is no next element.

If you had 3 elements in the beginning, removing one would result in hasNext to be 'true'. Then the following next will throw the expected exception.

The JavaDoc points out that the "fail-fast" functionality works based on "best effort" and that it shall be used merely for detecting bugs rather than really depending on it for the program to behave correctly. Obviously because of side-effects like this one.

Fildor
  • 14,510
  • 4
  • 35
  • 67
0

ConcurrentModificationException will throw, you can make some modifications in the list during iteration.

After doing the modification in the list during iteration, if you try to access the next() or remove() using iterator, then it verify the modCount and expectedModCount and count is not same then it throw ConcurrentModificationException .

final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
Thanigai Arasu
  • 413
  • 3
  • 14