Friday, 26 May 2017

java.util.ConcurrentModificationException

This post shows show to solve the problem of java.util.ConcurrentModificationException for ArrayList.

The error message looks like the following:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
...
...

The Problem


You may want to iterate through an ArrayList, and delete some element under some condition. For example, the following code looks reasonable:

import java.util.ArrayList;
import java.util.List;

public class AddRemoveListElement {

public static void main(String args[]) {
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");

for (String s : list) {
if (s.equals("B")) {
list.remove(s);
}
}
}
}

Output:

Oracle Java Guide, Oracle Java Materials

Solution 1


Iterator can be used to solve this problem. Iterators allow the caller to remove elements from the underlying collection during the iteration.

Iterator<String> iter = list.iterator();
while(iter.hasNext()){
String str = iter.next();
      if( str.equals("B") )
      {
        iter.remove();
      }
}

Solution 2


Instead of ArrayList, CopyOnWriteArrayList can be used to solve the problem. CopyOnWriteArrayList is a thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

public static void main(String args[]) {
List<String> list = new CopyOnWriteArrayList<String>();
list.add("A");
list.add("B");

for (String s : list) {
if (s.equals("B")) {
list.remove(s);
}
}
}

How about other Collection types?


public static void main(String args[]) {
Set<String> set = new HashSet<String>();
set.add("A");
set.add("B");

for (String s : set) {
if (s.equals("B")) {
set.remove(s);
}
}
}

public static void main(String args[]) {
LinkedList<String> llist = new LinkedList<String>();
llist.add("A");
llist.add("B");

for (String s : llist) {
if (s.equals("B")) {
llist.remove(s);
}
}
}

The above code is fine, because they do not use array as the underlining data structure.