java中的ConcurrentModificationException是什么异常?在哪些场景下会报该异常?
在软件构造实验Lab2的ConcreteVerticesGraph里,需要我们编写remove()方法。移除一个点没有别的方法,只有遍历集合vertices(),找到该点并移除。
当时我没有写上红框中的break,出现了ConcurrentModificationException的报错。写实验时没有仔细深究,上网搜索也没有看明白,写出break也是机缘巧合下想到了,后来搜索资料,详细地了解了一下这个报错。
异常简介
ConcurrentModificationException是基于java集合中的 快速失败(fail-fast) 机制产生的,在使用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了增删改,就会抛出该异常。
快速失败机制使得java的集合类不能在多线程下并发修改,也不能在迭代过程中被修改。
抛出异常的原因
在实验中,我们使用ArrayList的remove方法遍历并移除元素。
此时会抛出异常:
Exception in thread “main” java.util.ConcurrentModificationException
参考ArrayList的源码中关于remove的片段
1 public void remove() { 2 if (lastRet < 0) 3 throw new IllegalStateException(); 4 checkForComodification(); 5 6 try { 7 ArrayList.this.remove(lastRet); 8 cursor = lastRet; 9 lastRet = -1; 10 expectedModCount = modCount; 11 } catch (IndexOutOfBoundsException ex) { 12 throw new ConcurrentModificationException(); 13 } 14 } 15 final void checkForComodification() { 16 if (modCount != expectedModCount) 17 throw new ConcurrentModificationException(); 18 }
remove会检测是否有修改,判断依据为modCount != expectedModCount,每当变更列表,都会改变modCount的值,如果检测到modCount != expectedModCount,那么就会抛出Concurrent Modification Exception。
foreach循环遍历集合,实际上隐式调用了迭代器遍历,同样调用集合的remove或add等方法会抛异常;
解决方案
1.使用Iterator提供的remove方法,用于删除当前元素。
2.新建一个集合存放要删除的元素,之后统一删除。
3.不使用iterator遍历,但是这里要注意移除了一个元素,索引i也随之改变。
参考博客: