-1

According to the javadocs,conncurrent modification exception will be thrown when we will try to structurally modify the collection while iterating over it.Only iterator remove method will not throw concurrent modification exception.

I have analyzed following cases where concurrent modification exception will not be thrown:

List<Integer> var=new ArrayList<Integer>();
var.add(3);
var.add(2);
var.add(5);

1st case:

for(int i = 0; i<var.size(); i++){
    System.out.println(var.get(i));
    var.remove(i);
}

2nd Case:

for(Integer i:var){
    System.out.println(i);
    if(i==2){
        var.remove("5");
    }
}

1)Can anyone please explain how these cases are not throwing Conncurrent Modification Exception? 2)Can anyone please tell how iterator.remove internally works?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
mahan07
  • 887
  • 4
  • 14
  • 32
  • Well the first case doesn't use an iterator, for one thing... – Jon Skeet Feb 02 '16 at 18:52
  • If the ist case is not using iterator,it should throw concurrent modification exception – mahan07 Feb 02 '16 at 18:54
  • @pankaj why do you think that? How would you even think that could happen? `var` doesn't _know_ you're looping over its elements; it can't even tell. – Louis Wasserman Feb 02 '16 at 18:55
  • @Louis so you mean to say enhanced for loop internally used iterator. – mahan07 Feb 02 '16 at 18:58
  • Yes, the enhanced for loop uses an iterator. – Jon Skeet Feb 02 '16 at 18:58
  • @Jon@Louis But in the Ist case,let us suppose we have five elements so list size will be 5.Let us assume at 4th element,some condition satisfies and it removes the element,now the size will be reduced to 4 and loop terminates,so it is not at all processing 5th element,so should not it throw exception? – mahan07 Feb 02 '16 at 19:03
  • 2
    It is the *iterator* which throws the `ConcurrentModificationException`s, not the list - if there is no iterator, there's nothing to throw the CME. (`ArrayList` itself only throws a CME if a modification is detected whilst serializing the list - and you're not doing that here). – Andy Turner Feb 02 '16 at 19:05

2 Answers2

1

The first implementation isn't using an iterator, so of course it doesn't throw. It's only Iterators that throw (though even the indexed for-loop will be corrupted, e.g. if you remove an element and then the indexes of all the other elements shift out from under your iteration). Java just won't be able to tell you.

The second implementation isn't changing the contents. var.remove("5") attempts to remove the string "5", which isn't present (the list only contains integers), so no change happens. Additionally, i == 2 is dangerous when i is a boxed capital-I Integer; consider doing for (int i : var) instead.

Finally, no implementation guarantees that a ConcurrentModificationException will be thrown; it only tries to do so to warn you your iterator has been corrupted. Whether or not an exception is thrown, the iterator is corrupted by modifications performed while an iteration is in progress, Java's just trying to warn you.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 1
    Thanks Louis,Can you please tell how iterator.remove internally works,like will it remove the element and also decrease the excepted modcount? – mahan07 Feb 02 '16 at 19:00
  • 2
    ...yes? But the point is that if a modification happens from outside the iterator, then the iterator's internal index may be pointing to a different element than it used to be pointing to, meaning that you could skip an element or repeat an element or some other bad thing would happen. That's the point of doing remove from inside the iterator, so that its index can be kept consistent, not that any special magic happens. – Louis Wasserman Feb 02 '16 at 19:02
1

According to the Javadoc of ArrayList:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.

So, the conditions under which a CME will be thrown are:

  • There must be an iterator (or a list iterator)
  • You must perform a structural modification of the list not via the iterator (i.e. add or remove an element)

And, perhaps not quite so obviously:

  • After the structural modification, you must call a method on an iterator created before the structural modification.

i.e. the iterator doesn't attempt to detect the CME until you call next() or remove() on it.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243