集合框架之——迭代器并发修改异常ConcurrentModificationException

Posted Frank_Lei

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集合框架之——迭代器并发修改异常ConcurrentModificationException相关的知识,希望对你有一定的参考价值。

问题:
我有一个集合,如下,请问,我想判断里面有没有”world”这个元素,如果有,我就添加一个”javaee”元素,请写代码实现。

使用普通迭代器出现的异常:
ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

产生的原因:
迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
其实这个问题描述的是:普通迭代器遍历元素的时候,通过集合是不能修改元素的。

解决:
A:迭代器迭代元素,迭代器修改元素
   元素是跟在刚才迭代的元素后面的。
B:集合遍历元素,集合修改元素(普通for循环进行遍历)
   元素是在最后添加的。

 1 import java.util.ArrayList;
 2 import java.util.Iterator;
 3 import java.util.List;
 4 import java.util.ListIterator;
 5 
 6 public class ListIteratorDemo2 {
 7     public static void main(String[] args) {
 8         // 创建List集合对象
 9         List list = new ArrayList();
10         // 添加元素
11         list.add("hello");
12         list.add("world");
13         list.add("java");
14 
15         // 普通迭代器遍历
16         // Iterator it = list.iterator();
17         // while (it.hasNext()) {
18         // String s = (String) it.next();
19         // if ("world".equals(s)) {
20         // list.add("javaee"); //这里报错!!!!
21         // }
22         // }
23 
24         方式1:迭代器迭代元素,迭代器修改元素
25         而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator
26         ListIterator lit = list.listIterator();
27         while (lit.hasNext()) {
28             String s = (String) lit.next();
29             if ("world".equals(s)) {
30                 lit.add("javaee");
31             }
32         }
33 
34         方式2:集合遍历元素,集合修改元素(普通for)
35         for (int x = 0; x < list.size(); x++) {
36             String s = (String) list.get(x);
37             if ("world".equals(s)) {
38                 list.add("javaee");
39             }
40         }
41 
42         System.out.println("list:" + list);
43     }
44 }

另外,尤其值得注意的是此迭代器remove()方法的使用:从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法(remove方法)之外的其他方式修改了该迭代器所指向的 collection,则迭代器的行为是不确定的。 接口设计人员在设计Iterator<T>接口的时候已经指出,在进行迭代时如果调用了除了迭代器的remove()方法修改了该迭代器所指向的collection,则会造成不确定的后果。具体出现什么后果依迭代器的具体实现而定。针对这种不确定的后果可能出现的情况,在学习ArrayList时遇到了其中一种:迭代器抛出 ConcurrentModificationException异常。具体异常情况如下代码所示:

 1 import java.util.ArrayList;
 2 import java.util.Collection;
 3 import java.util.Iterator;
 4 
 5 public class ItaratorTest {
 6 
 7     public static void main(String[] args) {
 8         Collection<String> list = new ArrayList<String>();
 9         list.add("android");
10         list.add("ios");
11         list.add("Windows Mobile");
12 
13         Iterator<String> iterator = list.iterator();
14         while (iterator.hasNext()) {
15             String lang = iterator.next();
16             list.remove(lang);//will throw ConcurrentModificationException
17         }
18     }
19 
20 }

此段代码在运行时会抛出ConcurrentModificationException异常,因为我们在迭代器运行期间没有用iterator的remove()方法来删除元素,而是使用ArrayList的 remove()方法改变了迭代器所指向的collection。这就违反了迭代器的设计原则,所以发生了异常。

 

总结:

  • 在用迭代器Iterator遍历collection时,如果要在遍历期间修改collection,则必须通过Iterator/listIterator来实现,否则可能会发生“不确定的后果”。

以上是关于集合框架之——迭代器并发修改异常ConcurrentModificationException的主要内容,如果未能解决你的问题,请参考以下文章

JAVA集合02_List集合的概述并发修改异常迭代器遍历子类对比

ConcurrentModificationException(并发修改异常)的解决

List集合遍历时修改元素出现并发修改异常总结

集合并发修改异常-增强for循环,或者迭代器遍历的时候不可修改值

ConcurrentModificationException:并发修改异常

集合foreach迭代时,边迭代边删除,只能使用迭代器删除,不能使用集合删除,否则会导致并发修改异常for-each和Iterator的选择