为什么list不能在增强型循环遍历的时候用remove删除元素?

1、新人可能很常见的错误

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

    for (String s: list) {
        if (s.equals("1")) {
            list.remove(s);
        }
    }

    System.out.println(list);
}

这是你会觉得没什么问题,逻辑很清晰,然后你就去跑了一下发现一个错误

java.util.ConcurrentModificationException异常了,翻译成中文就是:并发修改异常。

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 shen.callable.XiaoMing.main(Main.java:33)

然后你换成删除2,你发现又可以了,再试下1又报错了,接下来我们就讲讲这是为什么?

 

2、分析为什么会出现这种情况

     我们打开target目录下找到这个文件的字节码文件你会发下它长这个样子去了

public static void main(String[] args) {
        List list = new ArrayList();
        list.add("1");
        list.add("2");
        list.add("3");
        Iterator var2 = list.iterator();

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

    }

从中我们可以看到list的增强型循环其实就是采用的iteratior形式,使用的核心方法是hasnext()和next()

(数组当然用不了迭代器就是普通的for循环,感兴趣的可以自己写一个看看)

我们接下来就看下list里的迭代器是如何实现的。

public Iterator iterator() {
        return new Itr();
}

很简单,就是new了一个对象而已,那这个对象是什么呢?我们继续点下去。

我们发现就在这个方法的下面,这个Itr是arrayList的一个内部类。

为什么list不能在增强型循环遍历的时候用remove删除元素?_第1张图片

当我们的代码执行到remove语句的时候

我们调用的是属于list的remove方法

为什么list不能在增强型循环遍历的时候用remove删除元素?_第2张图片

这里我们的modCount++了

而当我们再一次循环的时候,调用的是list内部类itr的next方法,我们可以跟进看下

为什么list不能在增强型循环遍历的时候用remove删除元素?_第3张图片

进入checkForComdification()方法

为什么list不能在增强型循环遍历的时候用remove删除元素?_第4张图片

大家可以返回上面的Itr内部类的大致图看下expectedModCount会等于什么,

在我们调用的list的remove的时候,modCount++了,而我们的expectedModCount是等于最开始modCount值

所以这里明显不等于了,条件为真,

throw new ConcurrentModificationException();

其实这条线路不难推断,跟着报错点进去就能发现。

其实究其原因就是因为增强型循环对于list的遍历采用的是迭代器。

 

3、那我们如何在遍历的时候删除一个元素呢?

我已知的有俩种方法:

1、直接使用最简单的for循环遍历,条件判断一定要用i

为什么list不能在增强型循环遍历的时候用remove删除元素?_第5张图片

2、使用迭代器的remove方法

这里又要插几句了,为什么迭代器的remove反法有用呢?如果细心观察了源码的朋友应该能看到为什么。

为什么list不能在增强型循环遍历的时候用remove删除元素?_第6张图片

这就是为什么迭代器的remove起作用的原因。

今天就说到这吧,最近在忙着找工作,因为只是普通二本的原因,困难重重,面试机会都没有。

你可能感兴趣的:(集合,源码分析,java,java)