Iterator/foreach遍历list时,删除list元素的时候报错问题

今天遇到一个问题,代码如下:

public class TestIter {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();;
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("dd");
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()) {
            String string = iterator.next();
            //aa bb dd均报错,唯独cc没问题
            if(string.equals("dd")) {
                list.remove(string);
            }
            
            System.out.println(list.toString());
        }
    }
}

创建了一个List<String>,然后给他add了4个元素,将list转为Iterator然后进行遍历,在遍历过程中对list进行remove,在测试的过程中,发现居然会出现报错现象,一直想不明白,后来根据报错信息去查找源码才发现问题所在。
先展示一下报错信息:

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at ace.zyi.yam.demo.TestIter.main(TestIter.java:17)

通过报错信息,我们可以看出执行next()方法的时候会进入checkForComodification()方法,这时候就报错了,那我们来看看这个方法内源码是怎么样的。。

final void checkForComodification() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
    }

看源码我们可以看到,之所以会报错是因为modCount != expectedModCount,那这两个变量分别是什么意思呢?
实际上,在我们将list转为Iterator的时候,会将modCount赋值给expectedModCount,这是iterator里的一个字面量,保存生成Iterator的时候,list中修改元素的次数,

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

通过查看add方法,我们可以看出,每进行一次add操作,就会进行自增,刚才我进行了4次,所以modCount是4,在生成Iterator的时候,expectedModCount也是4,

在遍历的时候,一定会经过两个方法,分别是hasNext()next()

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

cursor:这是Itr类(Iterator的一个子类),用来保存Iterator当前的位置信息,从0开始。
size:这是ArrayList的字段,因为Itr是一个内部类,所以直接调用了ArrayList的size字段。
实际上这就是当cursor != size的时候,就默认后面还有元素。
所以当我们进行remove删除元素的时候,modCount一样会进行自增,而原本是4,进行一次remove就是5了,所以当下一个元素进来执行next()方法的时候,就会出现modCount != expectedModCount了,所以就会报异常出来了。

但是是不是删除所有元素又都会报错呢?那又不是的,从我刚开始贴的代码就可以看到,倒数第二个元素是可以正常remove,而且还不会报异常的。
其实也是一个挺简单的道理,根据上面的分析,进入next()方法就会报异常,那我们在删除了元素以后,不进入这个方法就不会报异常了,也就是说hasNext()返回false,就会直接终止循环。

我们分析一下为什么倒数第二个不会报异常,看源码可以看出,倒数第二个元素的时候,Itr的cursor是3,当list删除掉一个元素的时候,size也是等于3,所以在判断的时候,cursor==size,因此就会在删除了一个元素以后,直接跳出循环,所以不会报异常了。

如果是使用Iteratorremove()方法就不会报异常了,因为这个方法里面对expectedModCount重新赋值。

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


作者:KingJack灬
链接:https://www.jianshu.com/p/747b30ba5b4c
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用foreach循环遍历list集合删除元素的方法如下: ```java List<String> list = new ArrayList<>(); list.add("stu1"); list.add("stu2"); list.add("stu3"); list.add("stu4"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (item.equals("stu2")) { iterator.remove(); } } System.out.println(list); ``` 在这个例子,我们首先创建了一个ArrayList集合,并向其添加了一些元素。然后,我们使用Iterator迭代器遍历集合元素。在遍历过程,我们使用if语句来判断当前元素是否需要删除,如果需要删除,则使用Iterator的remove()方法来删除元素。最后,我们打印出删除元素后的集合内容。 请注意,使用foreach循环遍历集合,不能直接在循环删除元素,因为这会导致ConcurrentModificationException异常。因此,我们需要使用Iterator来进行安全的删除操作。 #### 引用[.reference_title] - *1* [foreach遍历集合](https://blog.csdn.net/m0_53821599/article/details/119655736)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [mybatis使用foreach遍历list集合或者array数组方式](https://blog.csdn.net/weixin_43982687/article/details/126475109)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值