深究 java.util.ConcurrentModificationException
Exception in thread “main” java.util.ConcurrentModificationException
最近在对list 容器内进行遍历删除修改对象的时候报了这个错,问了下大佬自己去也去研究了一下,最后终于找到了原因,记个笔记。
一个简单的列子:
ArrayList<human> humans = new ArrayList<human>();
for(int i=0; i<10 ;i++) {
humans.add(new human(i));
}
for(human hu : humans) {
humans.remove(hu);
}
Iterator<human> it = humans.iterator();
while(it.hasNext()) {
human hu = it.next();
humans.remove(hu);
humans.add(hu);
}
执行上述任何一个代码会抛出 java.util.ConcurrentModificationException 异常。
所以foreach遍历list 里面还是调用了iterator进行迭代遍历的,那为什么会出现这个问题?
跟踪一下remove方法
发现有一个可疑的变量。
这里还提示了增加modCount
并且在其他只要是修改的方法也都会有这个变量。
接下
接着看下是怎么获取的.iterator();
是list的一个内部类并实现了Iterator接口
从next方法中看到其在每次获取下一个内容前都会进行某些检查,检查是否被修改。
那么到这里已经知道缘由了,当对list对象进行增删操作的时候都会进行使modCount++,并且当iterator被创建的时候将当前的modCount 赋值给expectedModCount,每次迭代遍历前都会检查modCount是否被改变,改变就给你抛出异常。
q1 那为啥要阻止我们这么干?
q2 我就是要进行修改操作该咋办?
a1:
参考了几篇博客,自己做一个简单的总结:
执行以下代码进行模拟:
ArrayList<human> humans = new ArrayList<human>();
humans.add(new human(a));
humans.add(new human(b));
humans.add(new human(c));
humans.add(new human(d));
Iterator<human> it = humans.iterator();
human hu = it.next();
执行上述代码数组容器是处于55行这样的一个情况,
但当我 再执行 humans.add(0,new human(x));
就变成了56行的样子,因为在数组前插入了一个数组导致了其他数据后移,此时就会导致少遍历数据了。因为next方法是返回内容并将指针后跳。但是插入删除都会造成其数组元素的移动,同理删除在某些情况也会影响,这里就不一一举例了。
a2:
iterator还提供了一个删除的方法可以快捷的删除内容。
`
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
通过一个lastRet定位当前节点的前一个节点,若前面一个节点内容被删除了就可以通过lastRet来处理元素变动的问题。