循环增删 ArrayList ,小心有坑
编程过程中常常需要使用到集合,比如: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/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2022-10-13 Mybatis-plus分页查询和条件查询通用写法- 动态接口参数