最近在写代码的时候遇到了遍历时删除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. MySql入门(2-1)windows下安装mysql的两种方式

    一.下载mysql 1.下载解压MySQL 登录oracle主页,需要用户名和口令: lshengqi@netease.com/1wsx**** 下载路径:: https://dev.mysql.co ...

  2. Java8新特性第3章(Stream API)

    Stream作为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream完全不是一个概念.Java8中的Stream是对集合功能的一种增强,主要用于对集合对象进 ...

  3. 如何从0开发一个Atom组件

    最近用Atom写博客比较多,然后发现一个很严重的问题..没有一个我想要的上传图片的方式,比如某乎上边就可以直接copy/paste文件,然后进行上传.然而在Atom上没有找到类似的插件,最接近的一个, ...

  4. Python/零起点(一、数字及元组)

    Python/零起点(一.数字及元组) int整型 int()强行转换成整型数据类型 int整型是不可变,且是不可迭代的对象 一.整型数字用二进制位数表示案例: age=7 #设定一个数字赋值给age ...

  5. python/ Django之中间件

    python/ Django之中间件 一.中间件 中间件共分为: (1)process_request(self,request) (2)process_view(self, request, cal ...

  6. I/O和管道

    一:I/O设备 I/O(Input/Output),即输入/输出,通常指数据在内部存储器和外部存储器或其他周边设备之间的输入和输出. 标准输入(STDIN):0 默认接受来自键盘的输入 标准输出(ST ...

  7. linux添加超级用户

    创建super账号 useradd testuser 创建用户testuser passwd testuser 给已创建的用户testuser设置密码 如果需要让此用户有root权限,执行命令: ro ...

  8. scrapy爬取全部知乎用户信息

    # -*- coding: utf-8 -*- # scrapy爬取全部知乎用户信息 # 1:是否遵守robbots_txt协议改为False # 2: 加入爬取所需的headers: user-ag ...

  9. sys.exc_info()可以捕获到任意异常

    import sys try: a = 3 assert a > 4 except: exc = sys.exc_info()#返回异常的元祖 print (exc)

  10. Windows Socket的UDP和TCP编程介绍

    1:网络中进程之间如何通信 为了实现进程之间通信,首要解决的问题是如何唯一标识一个进程,在本地可以通过进程PID来唯一标识一个进程,但是在网络中则是行不通的,其实TCP/IP协议族已经帮我们解决了这个 ...