class="java">package com.ljn.base; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * “对ArrayList进行遍历时,不要进行list.remove或者list.add操作” * 我只是记住了这条规则,但规则的背后,是什么原理? * 通过代码来说明: */ public class ConcurrentModificationExceptionTest { public static void main(String[] args) { remove(newArrayList(), "b"); remove(newArrayList(), "a"); } private static void remove(List<String> list, String itemToRemove) { Iterator<String> iterator = list.iterator(); int i = 1; while (iterator.hasNext()) { String item = iterator.next(); System.out.println(i++); if (item.equals(itemToRemove)) { list.remove(item); System.out.println(item + " is removed"); } else { System.out.println(item); } } System.out.println(); } private static List<String> newArrayList() { List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); return list; } /* 很简单的程序,输出如下: 1 a 2 b is removed 1 a is removed Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) at java.util.AbstractList$Itr.next(AbstractList.java:343) 为什么remove(newArrayList(), "a")会抛异常,而remove(newArrayList(), "b")就不会? AbstractList里面有一个字段modCount,用来记录List“结构性改变”的次数,执行add或者remove都会使得modCount加1 AbstractList.iterator会创建一个AbstractList.Itr(内部类),而Itr备份了modCount,命名为expectedModCount Itr执行next和remove操作前,都会调用checkForComodification方法检查expectedModCount是否等于modCount,如果不等, 就报ConcurrentModificationException 同时注意到Itr有一个指针cursor,表示下一个要遍历的元素的下标,初始值为0 Itr调用hasNext时,会将cursor与数组大小比较: public boolean hasNext() { return cursor != size(); } 回到例子 先看remove(newArrayList(), "a"): 1.newArrayList()之后,modCount=3 2.list.iterator()之后,Itr的expectedModCount=modCount=3 3.调用hasNext(),next(),再调用list.remove(item),此时modCount=4 4.调用hasNext(),next(),在next里面进行检查,发现expectedModCount不等于modCount,于是报错 再看remove(newArrayList(), "b"): 1.newArrayList()之后,modCount=3, list.size=3 2.list.iterator()之后,Itr的expectedModCount=modCount=3,cursor=0 3.调用hasNext(),next(),打印a,list.size=2,cursor=1;没有对list做修改,因此expectedModCount=3 4.调用hasNext(),next(),检查expectedModCount和modCount,都等于3,因此检查通过,b is removed; 此时cursor=2,size=2 5.调用hasNext,此时cursor 与 size()都等于2,hasNext返回false,循环结束 由此可见,remove(newArrayList(), "b")只是侥幸地成功运行了,但仍然是错误的用法 */ }