首页 > 其他分享 >循环增删 ArrayList ,小心有坑

循环增删 ArrayList ,小心有坑

时间:2023-10-13 09:56:54浏览次数:30  
标签:ArrayList 小心 add remove arrayList2 arrayList1 增删 new

编程过程中常常需要使用到集合,比如:ArrayList,当我们在 for 循环增删的时候,一不小心就会踩坑。

如下代码

List<String> arrayList1 = new ArrayList<String>();
arrayList1.add("1");
arrayList1.add("2");
for (String s : arrayList1) {
    if("1".equals(s)){
        arrayList1.remove(s);
    }
}

List<String> arrayList2 = new ArrayList<String>();
arrayList2.add("2");
arrayList2.add("1");
for (String s : arrayList2) {
    if("1".equals(s)){
        arrayList2.remove(s);
    }
}

但从代码逻辑上来看,似乎并没有什么问题

但是,当程序运行时,结果如下:

arrayList1的remove方法成功执行, arrayList2的remove方法运行抛出ConcurrentModificationException异常。

我们查看源代码来分析异常原因,因为foreach的本质就是使用迭代器Iterator,所有的Collecation集合类都会实现Iterable接口。

找到ArrayList类的iterator()方法

public Iterator<E> iterator() {
    return new Itr();
}

迭代器的本质是先调用hasNext()方法判断存不存在下一元素,然后再使用next()方法取下一元素

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\];
}

上面arraylist1为什么能remove成功呢?其实它只循环了一次,所以成功了。

因为它在remove元素1之后,它的size-1变成1,然后Itr内部的cursor变量由0变成1,此时1=1,循环结束,所以成功了。

arraylist2为什么remove失败呢?因为它在循环第二次的时候,也remove成功了,但是第三次判断next的时候cursor的值为2导致不等于现在的size 1,所以执行了next方法,最重要的来了,之前remove的操作导致ArrayList的modCount值加1,然后Itr类中的expectedModCount保持不变,所以会抛出异常。

final void checkForComodification() {
 if (modCount != expectedModCount)
     throw new ConcurrentModificationException();
}

同理可得,由于add操作也会导致modCount自增,所以不允许在foreach中删除, 增加,修改ArrayList中的元素。

对此,推荐大家使用迭代器Iterator删除元素。

Iterator<String> ite = arrayList2.iterator();
while(ite.hasNext()) {
 if("1".equals(ite.next())) {
  ite.remove();
 }
}

如果存在并发操作,还需要对Iterator进行加锁操作。

来源:toutiao.com/i6754322606561690116/

标签:ArrayList,小心,add,remove,arrayList2,arrayList1,增删,new
From: https://www.cnblogs.com/hefeng2014/p/17761190.html

相关文章

  • mongosh数据库增删改查
    通过MongoDBShell新建一个以自己名字(英文全拼,例如Sunjing)的数据库,并创建一个名为“grade”的集合,在该集合中插入自己上学期五门课程的成绩数据,具体包括课程名称,分数,任课教师,考试时间(或者其他相关信息)。并依次完成对数据进行增、删、改、查等基本操作,首先,打开MongoDBShell,连接......
  • SQL 语句 增删改查、边学习边增加中..... 这一部分为select
    SQL语句按照最大的类别分为1、增加insert 2、删除delete  https://www.cnblogs.com/kuangmeng/p/17756654.html3、修改update4、查询select: https://www.cnblogs.com/kuangmeng/p/17756425.html这一部分为select查询操作,以及对应的Leecode题,进行加......
  • ArrayList 介绍
       ......
  • 使用BAPI_NETWORK_COMP_*实现生产订单组件的增删改查
    1、文档说明对于生产订单组件的增删改有多种办法,比较常用的有使用内部函数CO_XT_COMPONENT_*,有改造BAPI_ALM_ORDER_MAINTAIN来实现,各有千秋。本文档介绍,通过PS的BAPI_NETWORK_COMP_*系列BAPI,来实现常见的组件先删后建的覆盖式操作,组件部分字段修改,组件信息查询等功能2、BAPI用......
  • fastapi-----SQLAlchemy对数据的增删改查操作(不使用crud+schemas)
     fromsqlalchemyimportcreate_engine,Column,String,Integerfromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.ormimportsessionmakerHOSTNAME='127.0.0.1'PORT="3306"USERNAME="root"PASSWORD=&......
  • ArrayList的线程安全问题简述,以及如何优化
    问题:创建一个ArrayList,然后创建两个线程,每个线程for循环1000次向公共的List里面添加数据,在一个线程读取List当前的大小之后,另一个线程可能已经对List进行了修改。这样就可能导致数据的不一致性,例如一个线程读取到的List大小已经被另一个线程修改了,因此,在这个案例中,最终的列表大小......
  • 有关于Mysql的简单问题及示例(增删改查 一对一 多对多 左外连接 右外链接)
    Mysql1、请自行设计表并针对该表练习最基本的增删改查且写出示例代码建立表格class其中有属性nameidgenderinterest表格建立完成向表中插入数据插入数据完成尝试删除表中id=101的数据删除数据成功尝试修改表中id为102的数据修改成功2、请问什么是一对多?请自......
  • JavaSE(08) - 集合 - ArrayList
    JavaSE(08)-集合-ArrayListp111ArrayList基本使用创建集合对象,泛型:限定集合中的数据类型.在jdk7中,后面的<>中可以不写数据类型.集合在底层做了一些处理,打印对象不是地址值,而是集合中存储的内容.publicclassArrayListBasic{publicstaticvoidmain......
  • Shell 数组的定义与增删改查
    Shell数组介绍为什么会产生Shell数组?通常在开发Shell脚本时,定义变量采用的形式为“a=1;b=2;c=3”,可如果有多个变量呢?这时再逐个地定义就会很费劲,并且要是有多个不确定的变量内容,也会难以进行变量定义,此外,快速读取不同变量的值也是一件很痛苦的事情,于是数组就诞生了,它就是为了解决......
  • C# efcode 新建表格数据 增删改查
    usingTestDbContextctx=newTestDbContext();varb1=newBook{AuthorName="杨中科",Title="零基础趣学C语言",Price=59.8,PubTime=newDateTime()};varb2=newBook{AuthorName="RobertSedgewick",......