测试代码为:
public static void main(String[] args) { List<String> strList = new ArrayList<String>(); strList.add("1"); strList.add("2"); strList.add("3"); strList.add("4"); for(String str:strList){ if(str.equals("4")){ strList.remove(str); } } }
运行后结果如下:
跟踪代码,抛出异常的地方具体在:
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }
遍历时返回一个元素之前,会调用checkForComodification()函数进行检查,该函数实现为:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount 为ArrayList修改的次数,expectedModCount 为期望修改的次数,在删除第四个元素之前,modCount 和expectedModCount 均为4,而调用ArrayList的remove()方法后,modCount 变为5,但expectedModCount 仍为4,因此出现上述异常。
解决方法为:使用 Iterator的remove()方法取代ArrayList的remove()方法,可以避免ConcurrentModificationException异常。
巧合的是,如果要删除的元素正好是集合中倒数第二个元素,则不会抛出此异常。Iterator遍历获取一个元素之前会先调用hasNext()方法来判断是否还有元素,该方法实现为:
public boolean hasNext() { return cursor != size(); }
其中cursor为遍历的位置,从0开始,在上面的next()方法中更新。
删除元素"3"后,cursor的值为3,而size()也返回3,hasNext()返回false,就不会调用next()方法了,因此也不存在ConcurrentModificationException异常。
删除元素"4"后,cursor的值变为4,而size()返回3,hasNext()返回true,调用next()方法时就会抛出ConcurrentModificationException异常。
附上一篇资料:
Java ConcurrentModificationException异常原因和解决方法:http://www.cnblogs.com/dolphin0520/p/3933551.html