遍历删除List中的元素有很多种方法,当运用不当的时候就会产生问题。下面主要看看以下几种遍历删除List中元素的形式:

1.通过增强的for循环删除符合条件的多个元素

2.通过增强的for循环删除符合条件的一个元素

3.通过普通的for删除删除符合条件的多个元素

4.通过Iterator进行遍历删除符合条件的多个元素

[java] view plaincopy
  1. /**
  2. * 使用增强的for循环
  3. * 在循环过程中从List中删除非基本数据类型以后,继续循环List时会报ConcurrentModificationException
  4. */
  5. public void listRemove() {
  6. List<Student> students = this.getStudents();
  7. for (Student stu : students) {
  8. if (stu.getId() == 2)
  9. students.remove(stu);
  10. }
  11. }
[java] view plaincopy
  1. /**
  2. * 像这种使用增强的for循环对List进行遍历删除,但删除之后马上就跳出的也不会出现异常
  3. */
  4. public void listRemoveBreak() {
  5. List<Student> students = this.getStudents();
  6. for (Student stu : students) {
  7. if (stu.getId() == 2) {
  8. students.remove(stu);
  9. break;
  10. }
  11. }
  12. }
[java] view plaincopy
  1. /**
  2. * 这种不使用增强的for循环的也可以正常删除和遍历,
  3. * 这里所谓的正常是指它不会报异常,但是删除后得到的
  4. * 数据不一定是正确的,这主要是因为删除元素后,被删除元素后
  5. * 的元素索引发生了变化。假设被遍历list中共有10个元素,当
  6. * 删除了第3个元素后,第4个元素就变成了第3个元素了,第5个就变成
  7. * 了第4个了,但是程序下一步循环到的索引是第4个,
  8. * 这时候取到的就是原本的第5个元素了。
  9. */
  10. public void listRemove2() {
  11. List<Student> students = this.getStudents();
  12. for (int i=0; i<students.size(); i++) {
  13. if (students.get(i).getId()%3 == 0) {
  14. Student student = students.get(i);
  15. students.remove(student);
  16. }
  17. }
  18. }
[java] view plaincopy
  1. /**
  2. * 使用Iterator的方式可以顺利删除和遍历
  3. */
  4. public void iteratorRemove() {
  5. List<Student> students = this.getStudents();
  6. System.out.println(students);
  7. Iterator<Student> stuIter = students.iterator();
  8. while (stuIter.hasNext()) {
  9. Student student = stuIter.next();
  10. if (student.getId() % 2 == 0)
  11. stuIter.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException
  12. }
  13. System.out.println(students);
  14. }

那么看到以上的几段代码之后,我们来分析一下他的原因,分析原因之前我们先来认识一个词fail-fast

百度百科是这么说的:

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
要了解fail-fast机制,我们首先要对ConcurrentModificationException 异常有所了解。当方法检测到对象的并发修改,但不允许这种修改时就抛出该异常。同时需要注意的是,该异常不会始终指出对象已经由不同线程并发修改,如果单线程违反了规则,同样也有可能会抛出改异常。
诚然,迭代器的快速失败行为无法得到保证,它不能保证一定会出现该错误,但是快速失败操作会尽最大努力抛出ConcurrentModificationException异常,所以因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。

当使用 fail-fast iterator 对 Collection 或 Map进行迭代操作过程中尝试直接修改 Collection / Map 的内容时,即使是在单线程下运行,java.util.ConcurrentModificationException 异常也将被抛出。

Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。

所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候,ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: itwould be wrong to write a program that depended on this exception forits correctness: ConcurrentModificationException should be used only todetect bugs.

附:来自ibm developerworks上对java.util.concurrent包的说明片段:
     java.util 包中的集合类都返回 fail-fast 迭代器,这意味着它们假设线程在集合内容中进行迭代时,集合不会更改它的内容。如果fail-fast 迭代器检测到在迭代过程中进行了更改操作,那么它会抛出 ConcurrentModificationException,这是不可控异常。
      在迭代过程中不更改集合的要求通常会对许多并发应用程序造成不便。相反,比较好的是它允许并发修改并确保迭代器只要进行合理操作,就可以提供集合的一致视图,如 java.util.concurrent 集合类中的迭代器所做的那样。
    java.util.concurrent 集合返回的迭代器称为弱一致的(weakly consistent)迭代器。对于这些类,如果元素自从迭代开始已经删除,且尚未由 next()方法返回,那么它将不返回到调用者。如果元素自迭代开始已经添加,那么它可能返回调用者,也可能不返回。在一次迭代中,无论如何更改底层集合,元素不会被返回两次。

fail-fast机制(遍历的同时删除List中的对象)相关推荐

  1. python删除对象引用_使用Python删除内存中的对象

    我正在尝试使用这种方法删除python中的对象.我阅读了Python的文档,声明垃圾收集器将自动删除未引用的对象.def check(): class newOb(): def __init__(se ...

  2. js删除数组中指定对象

    js删除数组中指定对象 需求说明 从数组中移除指定对象函数封装 `removeArray` 从数组中获取指定对象索引函数封装 `getArrayIndex ` 在`Vue`中调用函数使用 需求说明 点 ...

  3. JS删除数组中指定元素/删除数组中指定对象

    删除数组中指定对象指定元素 let arr = [{name: "xiaowang",id: 1 },, {name: "xiaozhang",id: 2 }, ...

  4. 删除数组中某个指定元素或删除数组中某个对象元素

    ES6--删除数组中某个指定元素或删除数组中某个对象 1.删除数组中某个指定元素 2.删除数组中的某个对象 1.删除数组中某个指定元素 let index = this.array.indexOf(n ...

  5. Java - Java集合中的快速失败Fail Fast 机制

    文章目录 什么是 fail-fast 源码解读 Itr 为什么对集合的结构进行修改会发生并发修改异常-源码分析 修改方法之 remove 修改方法之 add 案例分享 [案例一] [案例二] [案例三 ...

  6. Fail - Fast机制

    平常在使用集合的时候肯定会遇到过遍历删除集合中的某些元素,哪么在进行操作的时候大家有 没有遇到过什么问题呢?最近在使用集合进行遍历删除元素的时候,我就碰到了这个异常:java.util.Concurr ...

  7. 在c++中使用for循环遍历map并删除map中的元素的注意事项

    2019独角兽企业重金招聘Python工程师标准>>> 最近在写代码的过程中,发现了一处删除map元素导致的异常.主要是因为不安全的使用for循环遍历map并删除元素导致的. 我一开 ...

  8. 遍历并批量删除容器中元素出现ConcurrentModificationException原因及处置

    在以下四种遍历过程中,前两种会抛出ConcurrentModificationException,而后两种方法是正确的. Department类: package com.sitinspring; i ...

  9. vue根据对象id删除数组中的对象,实现局部刷新的功能

    方法一:使用过滤器 注:这个一般是根据对象id //tableData为原数组,row.id为将要删除的对象的id // 使用过滤器筛选出id不等于要删除的数据的所有对象,并将其重新赋值给list数组 ...

最新文章

  1. 视频|结构光编码与三维重建
  2. 怎样让小写自动转换成大写_办公软件操作技巧031:如何在word中输入大写数字...
  3. Python-turtle标准库知识小结(python绘图工具)
  4. 报告预测:到2027年,全球数据中心基础设施市场规模将达1423.1亿美元
  5. VMware VDI技术与实现
  6. 忘却的旋律java2_mc忘却的旋律启动器下载
  7. java与java ee_Java EE 8 MVC:全局异常处理
  8. Python之分组级运算——【transform()方法、apply()方法】
  9. 移位运算符 实现 二进制数的 高低位翻转(完整逻辑代码)
  10. MySQL存储过程中游标使用
  11. java获取局域网所有ip_java如何获取局域网内全部IP?
  12. ttf字体文件抽取自己想要的字
  13. 本地主机连接阿里云数据库(自建数据库)排雷
  14. qr码生成_在PHP中生成QR码
  15. 算法(arithmetic)
  16. 撒娇吧使大家啊让你撒何地什么科的你
  17. 【转】本人常用资源整理
  18. APISpace 静态活体检测API
  19. django框架全解
  20. 六大设计原则之开闭原则

热门文章

  1. java自学路线图_JAVA自学路线图
  2. python编辑程序模型_python并发编程之IO模型
  3. python基础语法+爬虫精进.pdf_风变编程《Python基础语法+爬虫精进》
  4. 一个测试工程师面试官的真实分享!个人超赞同!
  5. LeetCode 167 两数之和 II - 输入有序数组
  6. Nmap流量特征修改(NTA、IDS、IPS、流量审计)
  7. Linux日常运维管理技巧(二)Linux防火墙:你可以ping别人,别人ping不了你、转发、代理
  8. Dll注入技术之劫持注入
  9. Windows编程—控制面板程序显示信息修改(程序图标、名称、链接等)
  10. 第一次作业源于计科一班的王相博