首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

List删除异常原理

  • 25-04-18 03:05
  • 3835
  • 8374
juejin.cn

fori删除

fori 删除导致的异常

会报 indexOutBoundsException

fori循环是通过获取list中object[]数组的下标来循环获取数据的。一旦执行 list.remove(i) List中数组的数据

Object[] elementData 会执行 copy操作,数组index之后的所有数据会往前挪一位,同时把记录数组数量的字段size -1。

在这种情况下,当 i 为 2 时,list.remove(i) 会移除元素 "a",然后 ArrayList 会自动将后续元素前移并更新 size,使得原本在索引位置 2 的元素被移除,导致当前的 i 指向了下一个元素,但我们仍然继续访问原来的 i 索引位置,最终触发 IndexOutOfBoundsException。

csharp
代码解读
复制代码
   List list = new ArrayList<>();        list.add("b");        list.add("c");        list.add("a"); //会报查询索引的长度 < 数组的长度        for (int i = 0; i < list.size(); i++) {            if (list.get(i).equals("a")) {                list.remove(i);           }            // #1            System.out.println(list.get(i));       }

image-20250306093727929

foreach删除

foreach 删除导致的异常

会抛出 ConcurrentModificationException异常

erlang
代码解读
复制代码
for (String s : list){    if (s.equals("a")){       list.remove(s);   } }

foreach是语法糖,是为了java程序员加速开发做的优化,因为虚拟机是不认识foreach语法的,经过javac编译之后会变成原本的样子 虚拟机才能执行。

vbnet
代码解读
复制代码
Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) {    //#1 这里是关键点 这里会抛出 `ConcurrentModificationException`    String s = iterator.next();    if (s.equals("a")) {        //#2        list.remove(s);   } }

Interator是List内部的类,它的next方法如下,他会调用checkForComodification() , 这个方法会在校验expectedModCount与modCount。

arduino
代码解读
复制代码
 final void checkForComodification() {            if (modCount != expectedModCount)                throw new ConcurrentModificationException();       }

image-20250306100605286

初始化 Iterator的时候(这里是内部类class Itr)modCount与expectedModCount一致都是更改次数。当调用list.remove()的时候

会调用 fastMove()方法。而这个方法是把modCount++ 增加了1。而下次再循环的时候还会执行 Iterator.next()方法就会导致 expectedModCount与modCount不相等抛异常了。

image-20250306101153092

正确的方式

与上面的区别是 注意#1 位置,不要用list.remove() ,具体为啥上面已经说了。那为什么用iterator.remove就不会报错了了呢?

vbnet
代码解读
复制代码
       //不会报异常        Iterator<String> iterator = list.iterator();        while (iterator.hasNext()) {            String next = iterator.next();            if (next.equals("a")) {                //#1 这里不要用list.remove                iterator.remove();           }       }

iterator.remove()源码如下 注意 #2的位置,这里在删除之后会强行吧 expectedModCount = modCount这2个参数设置成一致,所以再调用.next()就不会抛出不一致的异常了。

csharp
代码解读
复制代码
public void remove() {            if (lastRet < 0)                throw new IllegalStateException();            checkForComodification();            try {               //调用父类的删除                ArrayList.this.remove(lastRet);                cursor = lastRet;                lastRet = -1;                // #2                expectedModCount = modCount;           } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();           }       }

ConcurrentModificationException 是为了避免并发修改引发不一致的状态,这个异常表明在遍历集合时集合结构被修改了(如通过 remove 方法)。Java 的 Iterator 保证在遍历时结构不会被改变,因此需要使用 iterator.remove() 来安全地删除元素。

注:本文转载自juejin.cn的佩服许仙的文章"https://juejin.cn/post/7478403990142500864"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

103
后端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top