为什么在foreach循环中进行元素remove/add操作,会抛ConcurrentModificationException 异常?

运行以下代码:

 @Test
    public void test() {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        for (String temp : list) {
            // 当为A时运行正常,改成B时异常ConcurrentModificationException
            if ("B".equals(temp)) {
                list.remove(temp);
            }
        }
    }

运行结果:

编译后的Class文件:

 @Test
    public void test() {
        List<String> list = new ArrayList();
        list.add("A");
        list.add("B");
        Iterator var2 = list.iterator();

        while(var2.hasNext()) {
            String temp = (String)var2.next();
            if("B".equals(temp)) {
                list.remove(temp);
            }
        }

    }

可以发现源码与编译后的字节码不一样,源码中的“for (String temp : list) {”在真实的字节码中是

“Iterator var2 = list.iterator();
while(var2.hasNext()) {
    String temp = (String)var2.next();”

对应的源码:

list.iterator()对应方法的源码:

new Itr()创建对象时,会将modCount值赋值给expectedModCount,而modCount该字段在ArrayList中标识当前对象的修改次数(包括remove和add方法)

add()

remove()

进入while循环时,执行var2.hasNext()方法:

cursor初始化的时候是0,每执行一次next()方法,值自动加1,cursor == size时会跳出循环

当执行next()方法时,首先会执行checkForComodification()方法

查看代码,可以看出当modCount != expectedModCount时,就会抛出ConcurrentModificationException

expectedModCount的值是在创建Itr对象赋值的,而遍历集合的时候,再执行一次remove或add就会导致modCount的值修改,而此时expectedModCount的值未变化,就会报异常ConcurrentModificationException。

如果非要在循环里面remove、add 元素,请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

  ListIterator iterator = list.listIterator();
        while (iterator.hasNext()) {
            String item = (String) iterator.next();
            if("B".equals(item)){
                iterator.add("C");
//                iterator.remove();
            }
            System.out.println("改变后的数据:" + list.toString());
        }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值