java.util.ConcurrentModificationException原因及解决办法

这个异常一般在我们遍历删除集合元素时出现。写了下面这个代码来展示这个异常。

[java]
import java.util.ArrayList;
import java.util.List;

public class ExeptionTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");

for (String s : list) {
if ("c".equals(s)) {
list.remove("c");
}
}
}
}
[/java]

控制台报错如下:

[java]
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at ExeptionTest.main(ExeptionTest.java:14)
[/java]

出现异常原因分析:

for循环执行时内部实际是调用的List实现了Iterator接口的方法,换句话说所有实现了Iterator接口的都可以使用for。追查JDK源码可以看到异常报错正是来自ArrayList内部实现的迭代器类Itr的checkForComodification()方法。

[java]
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
[/java]

其实这个方法只做了一件事就是检查迭代器当前的大小是否和原始大小一样,如果不一样。则认为原始的集合已经在其它地方被修改,故而出现此异常。

解决方法

既然报错的原因清楚了,那么我们只要不混用两种遍历方法就没有问题了。

[java]
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ExeptionTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");

// 法一
for (int i = 0; i < list.size(); i++) {
if (i == 2) {
list.remove(i);
}
}
System.out.println(list);

// 法二
Iterator iter = list.iterator();
while (iter.hasNext()) {
if ("d".equals(iter.next())) {
iter.remove();
}
}
System.out.println(list);
}
}

[/java]

ConcurrentModificationException进阶

某些时候我们可能会遇到遍历时还要再遍历删除的情况。这时该怎么解决呢?对于这样的情况我们有二种解决办法

  1. 将要删除的对象收集到另一个集合中一起删除[java]import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    public class ExeptionTest {
    public static void main(String[] args) {
    List list = new ArrayList();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");
    list.add("e");

    Iterator iter = list.iterator();
    List toBeRemove = new ArrayList();
    String t = null;
    while (iter.hasNext()) {
    t = iter.next();
    if (t.equals("c")) {
    toBeRemove.add(t);
    }
    }
    //使用removeAll一起删除
    list.removeAll(toBeRemove);
    System.out.println(list);

    }
    }[/java]

  2. 第一轮遍历时使用复制对象。[java]import java.util.ArrayList;
    import java.util.List;

    public class ExeptionTest {
    public static void main(String[] args) {
    List list = new ArrayList();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");
    list.add("e");
    // 遍历复制集合,此时实际使用的是iterator.
    for (String s : new ArrayList(list)) {
    if (s.equals("c"))
    //移除时使用的是非iterator的方式
    list.remove(s);
    }
    System.out.println(list);
    }
    }
    [/java]

本次的文章就写到这里,如有疏漏,欢迎指正。