首页 > 其他分享 >ArrayList remove删除元素 为什么会出现ConcurrentModificationException异常

ArrayList remove删除元素 为什么会出现ConcurrentModificationException异常

时间:2022-11-21 19:00:37浏览次数:73  
标签:Java ConcurrentModificationException ArrayList list remove next modCount size

ArrayList remove删除元素

先看代码

ArrayList<String> list = new ArrayList<>();
        list.add("Java");
		list.add("Python");
        for (String item : list) {
            if(item.equals("Java")){
                list.remove(item);
            }
        }

编译后

        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if ("Java".equals(next)) {
                list.remove(next);
            }
        }

这种情况下只能删除第一个元素,删除第二个元素会报错

991行报错的地方代码

为什么会存在modCount 和 expectedModCount?

首先modCount 是记录这个集合被操作的次数 add一个元素会加一,remove一个元素也会加一

添加一个元素

删除一个元素

expectedModCount 是内部类Itr中的一个属性默认赋值为modCount

Itr内部类的部分代码

    /**
     * An optimized version of AbstractList.Itr
     */
    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;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @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();
        }
    }

首先分析为什么删除第一个不会报错

        ArrayList<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if ("Java".equals(next)) {
                list.remove(next);
            }
        }

注意hashNext方法

cursor(0) size(2) hasNext checkForComodification
第一次循环 0 2 true true
第二次准备循环 1 1 false 不会进入

因为第一次循环if判断了两者相等 list 已经删除了Java 这个元素 size变成了1,由hasNext方法判断得出false 所以不会进入while循环。所以这只有一次循环。第二次准备循环是条件不满足退出了。

拿为什么删除第二个会报错

cursor(0) size(2) hasNext checkForComodification
第一次循环 0 2 true true
第二次循环 1 2 true true
第三次循环 2 1 true false 抛异常

第二次循环删除了一个元素 modCount+1 , size+1 ,cursor+1,所以hasNext是true ,在checkForComodification中 modCount !=expectedModCount所以会报错。

数学推理来了:

在单线程的情况下,只要你的ArrayList集合大小大于等于2(假设大小为n,即size=n),你删除倒数第二个元素的时候,cursor从0进行了n-1次的加一操作,size(即n)进行了一次减1的操作,所以n-1=n-1,即cursor=size。

因为判断条件返回为fales,虽然你的modCount变化了。但是不会进入下次循环,就不会触发modCount和expectedModCount的检查,也就不会抛出ConcurrentModifyException.

参考链接

【原创】这道Java基础题真的有坑!我求求你,认真思考后再回答
【原创】这道Java基础题真的有坑!我也没想到还有续集。

标签:Java,ConcurrentModificationException,ArrayList,list,remove,next,modCount,size
From: https://www.cnblogs.com/lyuSky/p/16912871.html

相关文章