迭代器边遍历边删除存在的问题

迭代器边遍历边删除存在的问题以及原理

01-问题

​ 我们先来看看如下代码

java 复制代码
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(4);
        list.add(3);
        list.add(2);
        list.add(7);
        list.add(0);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

​ 我们运行查看结果,可以正常运行输出,如下图所示

​ 上述是可以正常遍历的,我们修改一下代码再来运行

java 复制代码
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(4);
        list.add(3);
        list.add(2);
        list.add(7);
        list.add(0);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            list.remove(next);
            System.out.println(next);
        }
    }

​ 上述代码我们点击运行,会抛出异常,如下所示

我们来看一下问题所在。

02-原因分析

​ 我们点进去ArrayList获取迭代器的方法,可以看到返回了一个ListItr对象

​ 我们继续点进去,查看ListItr的源码,看到继承了Itr类,我们继续进入

​ 我们进入Itr的源码进行分析

java 复制代码
    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
        // 记录版本号信息,modCount是List继承的Abstract的
        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();
        }
    }

​ 我们首先关注到有三个属性,先来解释一下

  • **cursor:**下一个要访问元素的下标索引
  • **lastRet:**上一个访问过元素的下标索引
  • expectedModCount:我们可以看到这个属性赋值为modCount,我们点进去查看,发现其在List继承的AbstractList类中,我们翻译一下,可以看到其解释,原来这个是用来记录List被修改的次数,默认是0

​ 在我们使用List的add()、remove()、等方法的时候,会对modCount进行++的操作,表示该集合被修改的次数,我们注意到在迭代器的next()中,使用了checkForComodification()方法,在该方法中,当modCount != expectedModCount时,会抛出异常,可以看到我们一开始抛出的异常就是这个,原来在我们调用remove方法的时候,修改了modCount ,但是expectedModCount没变,所以导致不一致了。

那为什么要有这个机制呢,这个机制其实是一个类似于乐观锁一样,为了防止并发的时候使用迭代器遍历的时候,List被别的线程修改,导致出现的问题

相关推荐
Xiaouuuuua11 分钟前
我开源了一套springboot3快速开发模板
java·开发语言·开源
三好码农1 小时前
深入Android 15 Zygote:从进程孵化器到系统基石
java·架构
穆易青1 小时前
2025.06.20【pacbio】|使用Snakemake构建可重复的PacBio全基因组甲基化分析流程
java·运维·服务器
李明一.1 小时前
Java 全栈开发学习:从后端基石到前端灵动的成长之路
java·前端·学习
@佳瑞1 小时前
吐槽之前后端合作开发
java
小帅学编程2 小时前
Maven
java·maven
悟能不能悟2 小时前
在 MyBatis 的xml中,什么时候大于号和小于号可以不用转义
xml·java·mybatis
hqxstudying2 小时前
深入解析 Java List 实现类的底层原理
java·数据结构·算法·链表
猫头虎2 小时前
2025最新Python 100个常用函数在线体验项目
android·java·python·pycharm·django·pandas·pip