这篇文章是讨论如何解决ArrayList的java.util.ConcurrentModificationException异常问题。

错误的提示信息一般如下:

1
2
3
4
5
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
...
...

问题的根本原因

你可能是在迭代的同时根据某条件删除了一些元素。比如,下面的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
}
}
}
}

你将会得到如下错误:

ConcurrentModificationException 异常

解决方案1

可以使用Iterator来解决这个问题。Iterators可以在迭代的时候删除元素。

1
2
3
4
5
6
7
8
Iterator<String> iter = list.iterator();
while(iter.hasNext()){
String str = iter.next();
if( str.equals("B") )
{
iter.remove();
}
}

解决方案2

不使用ArrayList,改用CopyOnWriteArrayList来解决。CopyOnWriteArrayList 是线程安全的ArrayList,为了解决可变操作(add, set,等等),实现方式都是通过底层数组的复制。

1
2
3
4
5
6
7
8
9
10
11
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);
}
}
}

其他集合类型呢?

1
2
3
4
5
6
7
8
9
10
11
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);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
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);
}
}
}

上面的代码是可以的,因为它们没有使用阵列中的线数据结构。

参考文档