集合框架之——迭代器并发修改异常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来实现,否则可能会发生“不确定的后果”。