背景:在业务中遍历某个集合时涉及到排除某个属性为0的情况,即遍历时删除。

一、3种错误方式演示三种:

1.foreach

List<String> list = new ArrayList();list.add("1");list.add("2");list.add("3");list.add("4");list.add("5");
for(String ele: list){if(ele.equals("3")){System.out.println(ele);list.remove(ele);}
}
System.out.println(list.size());

2.Iterator

List<String> list = new ArrayList();
for (int i = 1; i <= 5; i++){list.add(i+"");
}
Iterator<String> iterator = list.iterator();while (iterator.hasNext()){String ele = iterator.next();if(ele.equals("3")){System.out.println(ele);list.remove(ele);}}
System.out.println(list.size());

以上两段代码的执行结果都是 java.util.ConcurrentModificationException。

在使用ArrayList时,当尝试用foreach或者Iterator遍历集合时进行删除或者插入元素的操作时,会抛出这样的异常:java.util.ConcurrentModificationException。

关于这个异常的原因,详情请看https://blog.csdn.net/qq_33535433/article/details/90667425?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control简单来说就是:ArrayList的父类AbstarctList维护了一个属性modCount,我们每次对集合进行修改(增添、删除元素等)时,modCount都会+1

而以foreach本质上是使用iterator遍历,内部会生成一个迭代器iterator。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候期望List中修改元素的次数,该变量初始时和modCount方法相等。如果你在遍历过程中删除元素,ListmodCount就会变化。

next方法中会调用checkForComodification()方法,若modCount != expectedModCount则会抛出java.util.ConcurrentModificationException异常,这是为了安全考虑。代码如下

 @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();}

既然上述方式都不行,那么用下标来遍历呢?即普通for循环

3.普通for循环

List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(2);list.add(2);list.add(2);for(int i = 0; i < list.size(); i++){if(list.get(i) == 2){list.remove(i);}}System.out.println(list.size()); //结果为3/*** 循环流程:* 第一次循环:size = 5  i = 0  此时值为1* 第二次循环:size = 5  i = 1  此时值为2,删除后,size变为4* 第三次循环:size = 4  i = 2  此时值为2,删除后,size变为3* 第四次循环:size = 3,不符合条件,跳出循环,* 即随着你删除元素,list的大小也在自动变小,这不是我们所能控制的,* 即使将i < list.size()改为i < 5,也会报java.lang.IndexOutOfBoundsException,即超出边界*/

二、解决办法

1.使用迭代器的remove方法

因为Iterator的remove方法中 有如下的操作:

expectedModCount = modCount;所以避免了ConcurrentModificationException的异常

 List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(2);list.add(2);list.add(2);Iterator<Integer> iterator = list.iterator();while (iterator.hasNext()){Integer ele = iterator.next();if(ele == 2){iterator.remove();}}System.out.println(list.size());

其中迭代器的remove相关代码如下:

 public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount; //处理代码} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}

阿里巴巴Java开发手册中原话:不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

2.倒序遍历删除

List<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(2);list.add(2);list.add(2);for (int i = list.size() - 1; i >= 0; i--){if(list.get(i) == 2){list.remove(i);}}System.out.println(list.size());  //size 为1/*** 循环流程:* 第一次循环:size = 5  i = 4  此时值为2, 删除后,size变为4* 第二次循环:size = 4  i = 3  此时值为2,删除后,size变为3* 第三次循环:size = 3  i = 2  此时值为2,删除后,size变为2* 第四次循环:size = 2  i = 1  此时值为2,删除后,size变为1* 第五次循环:size = 1  i = 0  此时值为1超出边界*/

可见,倒序遍历,每次删除一个元素size的改变未对遍历造成影响,且元素的前移也不会对倒序遍历有影响。最后两种方式修改集合均可,但集合存储大量的数据情况下,迭代器的速度更快

List集合遍历时如何删除元素相关推荐

  1. java_基础_遍历map删除元素_Java 遍历Map(包括集合)时,修改删除元素

    转载自:https://blog.csdn.net/weixin_33498283/article/details/114071025 1.遍历Map集合的四种方法 public staticvoid ...

  2. java利用循环打印AVA_ava.util.ArrayList在foreach循环遍历时可以删除元素

    ArrayList是java开发时非常常用的类,常碰到需要对ArrayList循环删除元素的情况.这时候大家都不会使用foreach循环的方式来遍历List,因为它会抛java.util.Concur ...

  3. java动态删除map元素报错_java map使用迭代器遍历时执行删除元素报空指针异常

    我建立了两个Map,其流程是遍历两个map,将map1中value值与map2中相同,但是K值不同的数据查找出来.然后把这条数据从Map2中删除.我使用迭代器在执行移除的时候是报空指针(java.la ...

  4. C++中反向遍历map时怎样删除元素

    文章目录 前言 map的正向遍历 map 遍历时删除元素 map 的反向遍历 map 反向遍历时删除元素 总结 前言 今天在解决一个问题 <5710. 积压订单中的订单总数> 时用到了ma ...

  5. Python简单遍历字典及删除元素的方法

    Python简单遍历字典及删除元素的方法 这篇文章主要介绍了Python简单遍历字典及删除元素的方法,结合实例形式分析了Python遍历字典删除元素的操作方法与相关注意事项,需要的朋友可以参考下 具体 ...

  6. python字典删除元素_Python简单遍历字典及删除元素的方法

    本文实例讲述了Python简单遍历字典及删除元素的方法.分享给大家供大家参考,具体如下: 这种方式是一定有问题的: d = {'a':1, 'b':2, 'c':3} for key in d: d. ...

  7. python 字典遍历删除_Python简单遍历字典及删除元素的方法

    本文实例讲述了Python简单遍历字典及删除元素的方法.共享给大家供大家参考,详细如下: 这种方式是一定有问题的: d = {'a':1, 'b':2, 'c':3} for key in d: d. ...

  8. 列表和字典循环遍历时的删除问题,集合

    1.for 循环的问题 : for 循环后面也有else,也可以使用break和continue(使用方法跟while一样). while    条件:                   for  ...

  9. 集合添加元素python_Python基础:列表、字典、元组、集合、添加和删除元素,增删...

    列表(有序) 添加 list.append(元素):在列表末尾添加新的元素 list.extend(seq):在列表末尾一次性追加另一个序列中的多个值 –seq可以是列表.元组.字典,若为字典,则仅会 ...

最新文章

  1. [Everyday Mathematics]20150107
  2. babel 编译vue_如何对代码进行未来验证:使用Babel polyfills编译JavaScript VS
  3. 在Ubuntu 14 04安装和使用Docker
  4. 2021牛客暑期多校训练营8,签到题ADEK
  5. linux date 得到指定 datemonth 月的 开始一天 结束一天
  6. Atitit.gui api自动化调用技术原理与实践
  7. 64位电脑上安装MySQL进行MFC开发的相关问题
  8. “无法保存该网页”的最简单解决方法
  9. 异常详细信息: System.Web.HttpException: 服务器太忙
  10. adobe怎么统计字数_pdf文件怎么快速统计字数?
  11. 4python小项目---# 体脂率计算
  12. 外卖私域流量:微信社群的运营和羊毛经济
  13. Python——基础语法
  14. kde 崩溃,如何重启 kde plasma 5 桌面
  15. windows10修改用户名解决CDK闪退问题
  16. C语言编译器Visual C++(中文版)的安装
  17. 【区块链技术开发】剖析区块链Ganache模拟器工具及其智能合约部署区块链的查询方式
  18. 面试官刁难:Java字符串可以引用传递吗?
  19. 线上O2O商城系统怎么做好运营 O2O成为商业模式需要哪些条件?
  20. 实验1 算法设计与分析

热门文章

  1. 京东内部员工吐槽,结果网友集体反水
  2. 【硬件】关于后期的硬件知识初步详解
  3. html 弹窗提示框,js弹出框、对话框、提示框、弹窗总结
  4. 用myqr输出炫丽二维码
  5. gitlab怎么删除创建的项目
  6. glup 和 webpack 的不同之处总结
  7. Linux重定向符号和特殊符号
  8. 使用jmeter进行并发测试
  9. 串口通信——串口接收数据,发送数据
  10. 静态数据static