解读阿里巴巴Java手册:为什么在foreach中禁止add/remove操作

foreach介绍

foreach是Java1.5引入的语法糖,语法糖写法简洁明了,容易被人理解,更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,但是不了解语法糖实现的原理很容易导致编写的代码运行时错误。

错误的例子

	public static void main(String[] args) {
		List<String> nums = new ArrayList<String>();
		nums.add("1");
		nums.add("2");
		nums.add("3");

		for (String num : nums) {
		    if (num.equals("3")) {
		    	nums.remove(num);
		    }
		}

	}

此段代码在编码阶段工具是不会报错的,但是运行时就会报出java.util.ConcurrentModificationException错误,我们先通过反编译来查看foreach会被Java编译器如何实现,关于如何反编译请查看https://blog.csdn.net/ren365880/article/details/108227239



    public static void main(String args[])
    {
        ArrayList arraylist = new ArrayList();
        arraylist.add("1");
        arraylist.add("2");
        arraylist.add("3");
        Iterator iterator = arraylist.iterator();
        do
        {
            if(!iterator.hasNext())
                break;
            String s = (String)iterator.next();
            if(s.equals("3"))
                arraylist.remove(s);
        } while(true);
    }

通过查看反编译后的文件可以看到,Java底层使用的迭代器实现的foreach。

一步步发现为什么报错

先看一下报的什么错,在什么文件哪一行报的错:

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.proxy.Test.main(Test.java:15)

可以看到,调用了ArrayList的checkForComodification方法报错,定位到错误行
在这里插入图片描述
可以看到,当变量modCount != expectedModCount的时候,就会抛ConcurrentModificationException。
modCount和expectedModCount变量是什么意思呢?

modCount:

此列表在结构上进行修改的次数。结构修改是更改列表大小的修改。
该字段由iterator和listIterator方法返回的迭代器和列表迭代器实现使用。如果此字段的值意外更改,则迭代器(或listiterator)将抛出ConcurrentModificationException,以响应下一个,移除,上一个,设置或添加操作 。 提供了快速故障行为以面对迭代期间的并发修改。

expectedModCount

期望被修改的次数。

这两个参数什么时候设置的呢?

首先先看ArrayList的调用的迭代器:
在这里插入图片描述
它返回了一个Itr类的示例,Itr是如何实现的呢?
在这里插入图片描述

可以看到,在初始化时 设置 expectedModCount = modCount;并且在获取迭代器下一个是进行了checkForComodification()方法验证。

为什么add/remove后2个参数就不一致了?

先看删除方法是如何实现的:
在这里插入图片描述
在这里插入图片描述
可以看到只是modCount增加了。再看添加:

在这里插入图片描述
在这里插入图片描述
也是只增加了modCount,modCount != expectedModCount在next方法检查时就会报错!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦里藍天

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值