欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

深究 java.util.ConcurrentModificationException

程序员文章站 2022-03-15 22:44:12
...

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方法
深究 java.util.ConcurrentModificationException
发现有一个可疑的变量。
深究 java.util.ConcurrentModificationException这里还提示了增加modCount
深究 java.util.ConcurrentModificationException并且在其他只要是修改的方法也都会有这个变量。
接下
接着看下是怎么获取的.iterator();
是list的一个内部类并实现了Iterator接口
从next方法中看到其在每次获取下一个内容前都会进行某些检查,检查是否被修改。
深究 java.util.ConcurrentModificationException那么到这里已经知道缘由了,当对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();
		

深究 java.util.ConcurrentModificationException执行上述代码数组容器是处于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来处理元素变动的问题。

相关标签: 学习笔记 java