最近在写代码的时候遇到了遍历时删除List元素的问题,在此写一篇博客记录一下。

一般而言,遍历List元素有以下三种方式:

  • 使用普通for循环遍历
  • 使用增强型for循环遍历
  • 使用iterator遍历

使用普通for循环遍历

代码如下:
  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new ArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. for (int i = 0; i < list.size(); i++) {
  8. // index and number
  9. System.out.print(i + " " + list.get(i));
  10. if (list.get(i) % 2 == 0) {
  11. list.remove(list.get(i));
  12. System.out.print(" delete");
  13. i--; // 索引改变!
  14. }
  15. System.out.println();
  16. }
  17. }
  18. }

结果如下:
 
可以看到遍历删除偶数的结果是成功的,但是这种方法由于删除的时候会改变list的index索引和size大小,可能会在遍历时导致一些访问越界的问题,因此不是特别推荐。
 

使用增强型for循环遍历

  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new ArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. for (Integer num : list) {
  8. // index and number
  9. System.out.print(num);
  10. if (num % 2 == 0) {
  11. list.remove(num);
  12. System.out.print(" delete");
  13. }
  14. System.out.println();
  15. }
  16. }
  17. }

结果如下:

 
可以看到删除第一个元素时是没有问题的,但删除后继续执行遍历过程的话就会抛出ConcurrentModificationException的异常。
 

使用iterator遍历

  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new ArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. Iterator<Integer> it = list.iterator();
  8. while (it.hasNext()) {
  9. // index and number
  10. int num = it.next();
  11. System.out.print(num);
  12. if (num % 2 == 0) {
  13. it.remove();
  14. System.out.print(" delete");
  15. }
  16. System.out.println();
  17. }
  18. }
  19. }

结果如下:

 
可以看到顺利的执行了遍历并删除的操作,因此最推荐的做法是使用iterator执行遍历删除操作。
 
以上是关于非线程安全的ArrayList,如果是线程安全的CopyOnWriteArrayList呢?
 

使用普通for循环遍历

 
  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new CopyOnWriteArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. for (int i = 0; i < list.size(); i++) {
  8. // index and number
  9. System.out.print(i + " " + list.get(i));
  10. if (list.get(i) % 2 == 0) {
  11. list.remove(list.get(i));
  12. System.out.print(" delete");
  13. i--; // 索引改变!
  14. }
  15. System.out.println();
  16. }
  17. }
  18. }

结果如下:

可以看到遍历删除是成功的,但是这种方法由于删除的时候会改变list的index索引和size大小,可能会在遍历时导致一些访问越界的问题,因此不是特别推荐。
 

使用增强型for循环遍历

  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new CopyOnWriteArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. for (Integer num : list) {
  8. // index and number
  9. System.out.print(num);
  10. if (num % 2 == 0) {
  11. list.remove(num);
  12. System.out.print(" delete");
  13. }
  14. System.out.println();
  15. }
  16. }
  17. }

结果如下:

 
可以看见与ArrayList遍历删除时情况不同,CopyOnWriteArrayList是允许使用增强型for进行循环遍历删除的。
 

使用iterator遍历

  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. List<Integer> list = new CopyOnWriteArrayList<>();
  4. for (int i = 0; i < 5; i++)
  5. list.add(i);
  6. // list {0, 1, 2, 3, 4}
  7. Iterator<Integer> it = list.iterator();
  8. while (it.hasNext()) {
  9. // index and number
  10. int num = it.next();
  11. System.out.print(num);
  12. if (num % 2 == 0) {
  13. it.remove();
  14. System.out.print(" delete");
  15. }
  16. System.out.println();
  17. }
  18. }
  19. }

结果如下:

 
与ArrayList不同,由于CopyOnWriteArrayList的iterator是对其List的一个“快照”,因此是不可改变的,所以无法使用iterator遍历删除。
 
综上所述,当使用ArrayList时,我们可以使用iterator实现遍历删除;而当我们使用CopyOnWriteArrayList时,我们直接使用增强型for循环遍历删除即可,此时使用iterator遍历删除反而会出现问题。

正确在遍历中删除List元素的更多相关文章

  1. List在遍历中删除t元素

    法一:使用普通for循环遍历 注意: 1.从头开始循环,每次删除后 i  减一.             2.从尾开始循环. public class Main { public static voi ...

  2. java 在循环中删除数组元素

    在写代码中经常会遇到需要在数组循环中删除数组元素的情况,但删除会导致数组长度变化. package com.fortunedr.thirdReport; import java.util.ArrayL ...

  3. ES6数组中删除指定元素

    知识点: ES6从数组中删除指定元素 findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引.否则返回-1. arr.splice(arr.findIndex(item => ...

  4. C#实现在foreach遍历中删除集合中的元素(方法总结)

    目录 方法一:采用for循环,并且从尾到头遍历 方法二:使用递归 方法三:通过泛型类实现IEnumerator 在foreach中删除元素时,每一次删除都会导致集合的大小和元素索引值发生变化,从而导致 ...

  5. 【坑】Java中遍历递归删除List元素

    运行环境 idea 2017.1.1 需求背景 需要做一个后台,可以编辑资源列表用于权限管理 资源列表中可以有父子关系,假设根节点为0,以下以(父节点id,子节点id)表示 当编辑某个资源时,需要带出 ...

  6. Java集合类ArrayList循环中删除特定元素

    在项目开发中,我们可能往往需要动态的删除ArrayList中的一些元素. 一种错误的方式: <pre name="code" class="java"&g ...

  7. 如何python循环中删除字典元素

    //下面这行就是在循环中遍历删除字典元素的方法! for i in list(dictheme2.keys()): if dictheme2[i]<self.countFortheme: dic ...

  8. LeetCode 82,考察你的基本功,在有序链表中删除重复元素II

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题的第51篇文章,我们来看LeetCode第82题,删除有序链表中的重复元素II(Remove Duplicates ...

  9. python中删除某个元素的3种方法

    python中关于删除list中的某个元素,一般有三种方法:remove.pop.del 1.remove: 删除单个元素,删除首个符合条件的元素,按值删除 举例说明: >>> st ...

随机推荐

  1. angular2 学习笔记 ( angular cli & npm version manage npm 版本管理 )

    更新 : 2017-05-05 现在流行 Yarn ! 它是 facebook google 推出的东西. 算是补助 npm 做的不够好的地方. 源码依然是发布去 npm,只是下载接口换掉罢了哦. n ...

  2. 云+社区技术沙龙:Kafka meetup 深圳站报名开启

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 如果说 2018 年是技术大爆炸年,那么 Apache Kafka 绝对是其中闪亮的新星. 自Kafka 从首发之日起,已经走过了快八个年头 ...

  3. jdk的server模式修改无效(关于client和server模式)

    本机为64位操作系统,64位jdk,win10. 修改C:\Program Files\Java\jre8\lib\amd64\jvm.cfg无效. 我的文件的内容为: 原因参考如下: http:// ...

  4. hdu4864 Task贪心好题

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4864 题目大意: 有n个机器,m个任务.每个机器至多能完成一个任务.对于每个机器,有一个最大运行时间 ...

  5. JSON序列化类

    '''pyhton的dict对象可以直接序列化为JSON的{},不过很多时候 我们更喜欢用class表示对象,比如定义Student类,然后序列化''' import json class Stude ...

  6. EFCore CodeFirst 连接MySql

    一.工具及环境 Visual Studio 2017 15.4.3 MySql Navicat for MySQL 二.Entity Framwork Core 2.0 MySql Code Firs ...

  7. 涨薪必备Javascript,快点放进小口袋!

    摘要: 嗨,新一年的招聘季,你找到更好的工作了吗?小姐姐最近刚换的工作,来总结下面试必备小技能,从this来看看javascript,让我们更深入的了解它. 前言 在JavaScript中,被吐槽最多 ...

  8. SQL Server 查询性能优化——创建索引原则(二)

    三:索引的建立原则 一般来说,建立索引要看数据使用的场景,换句话来说哪些访问数据的SQL语句是常用的,而这些语句是否因为缺少索引(也有可能是索引过多)变的效率低下.但绝不是所有的SQL语句都要建立索引 ...

  9. v-bind特性

    插值语法不能作用在 HTML 特性上,因此使用 v-bind 指令1.v-bind在一般特性上的使用:如id,src,disabled,checked,selected,name html: < ...

  10. java中关于&、&&、|、||之间的区别和运算

    关于&.&&.|.||之间的区别和运算 在逻辑运算中: 普通与&:要判断所有的判断的条件 短路与&&:如果前面一个判断条件出现false,则后续的判断条 ...