6

I was reading this "Freuqent Java concurrency problems" question and got confused by an answer talking about java.util.ConcurrentModificationException.

My understanding of the answer is that this can occur in a single-threaded program. How or what conditions cause the following code to throw the exception?

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }
Community
  • 1
  • 1
ArturPhilibin
  • 922
  • 2
  • 12
  • 25

3 Answers3

14

This snippet will always throw a ConcurrentModificationException.

The rule is the following: You may not modify (add or remove elements from the list) while iterating over it using an Iterator (which happens when you use a for-each loop).

Note however that you are allowed to modify the list through the iterator (because then it is aware of the modification, and can take it into account) using the Iterator.remove or ListIterator.add.

From the docs:

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.

The word concurrent here refers to that you're modifying the list during traversal.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • Technically you *can* remove from the list while you iterate over it as long as you use the iterator's `remove` method (not available though with a for/each loop). – Kevin Brock Feb 19 '11 at 16:24
  • @kevin if i modify the iterator structure without using the remove method , then does itthrows ConcurrentModificationException,or only when we use iterator's remove method. – Dead Programmer Feb 20 '11 at 10:14
  • If you're using the `Iterator.remove` method to modify the collection, no exception will be thrown. – aioobe Feb 20 '11 at 10:22
2

You are changing a list as you loop through it.

Here ConcurrentModificationException has nothing to do with threads.

Warning! The following example is here to show how it may be dangerous to use a collection as you change it. It's not what exactly happened in OP's case (looping through iterator and changing)

I think it would be easier to imagine what's wrong with it if you use an old-fashioned loop with a counter like this:

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

for (int i = 0; i < list.size(); i++) { 
   list.remove(i);  //removes element at given index
} 

Now, the first time i is 0, and 0th element is removed. The second time i is 1, so now 1st element is removed. But, what is now 1st, used to be 2nd, before the first removal. So, what used to be 1st, and now is 0th, will never be removed.

Goran Jovic
  • 9,418
  • 3
  • 43
  • 75
2

Because you are deleting from a list and iterating on it using a iterator at the same time.

See equivalent code using iterator.

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          String a=itr.next();
           list.remove(a);
      }
   }
}

Right code is

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          itr.remove();
      }
   }
}
Zimbabao
  • 8,150
  • 3
  • 29
  • 36