zoukankan      html  css  js  c++  java
  • ArrayList在foreach循环的时候remove元素报错

    示例代码:

    public class ArrayListTest {
    	public static void main(String[] args) {
    		List<String> list = new ArrayList<String>();
    		list.add("hello");
    		list.add("hello1");
    		list.add("hello2");
    		list.add("hello3");
    		list.add("hello4");
    		list.add("hello5");
    		for(String s : list){
    			list.remove("hello2");
    		}
    	}
    }
    

    报错结果:

    Exception in thread "main" java.util.ConcurrentModificationException
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    	at java.util.ArrayList$Itr.next(ArrayList.java:851)
    	at com.collection.list.ArrayListTest.main(ArrayListTest.java:18)
    

    再看这个问题之前大家先来了解一下foreach的本质是什么,
    参考此博文:https://blog.csdn.net/wangjun5159/article/details/61415263,foreach只是语法糖,本质还是
    for(Iterator i$ = a.iterator(); i$.hasNext(); System.out.print(temp));

    然后追踪栈轨迹看看源码:

    @SuppressWarnings("unchecked")
    public E next() {
        checkForComodification();//问题出在这行代码,然后看这个方法是什么?
        int i = cursor;
        if (i >= size)
            throw new NoSuchElementException();
        Object[] elementData = ArrayList.this.elementData;
        if (i >= elementData.length)
            throw new ConcurrentModificationException();
        cursor = i + 1;
        return (E) elementData[lastRet = i];
    }
    
    final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }
    

    上面两个方法都是private class Itr implements Iterator 这个迭代器实现类的方法。有上面两个方法可以明显的看出 if (modCount != expectedModCount)这个判断上,是这两个值不相等导致抛出了异常,那么这两个值又是什么呢?

    //The number of times this list has been <i>structurally modified</i>.
    protected transient int modCount = 0;
    
    private class Itr implements Iterator<E> {
       int cursor;       // index of next element to return
       int lastRet = -1; // index of last element returned; -1 if no such
       int expectedModCount = modCount;
    }
    

    modCount变量是ArrayList继承的抽象类AbstractList中一个变量,它表示的是对list的修改次数,而迭代器中的expectedModCount 在初始的时候,将modCount赋给了expectedModCount ,通过上面foreach我们看得到迭代器是在已进入for循环的时候初始的这时候modCount是未进行修改的,但是接下来remove有干了什么呢?

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
    

    如上代码,看到remove的元素如果存在的话会进入下面这个方法:

    private void fastRemove(int index) {
        modCount++;//在这里操作了modCount这个变量
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, 
    	        index,numMoved);
        elementData[--size] = null; // clear to let GC do its work
    }
    

    看到这里我们明白了什么时候改变了modCount导致和expectedModCount 不一致抛出了错误。

  • 相关阅读:
    ASCII码对照表 And HTML字符实体
    操作系统自带命令查看文件的哈希
    HMAC简介及HMAC-SHA256实现Demo
    CSV文件注入漏洞简析
    Kubernetes集群的安全机制
    Kubernetes -- Horizontal Pod Autoscaler
    获取两坐标之间距离
    在CentOS 7中搭建Git服务器
    centos7 搭建svn服务器
    node.js依赖express解析post请求四种数据格式()
  • 原文地址:https://www.cnblogs.com/Kevin-1992/p/12608368.html
Copyright © 2011-2022 走看看