`

正确在遍历中删除List元素

    博客分类:
  • JAVA
 
阅读更多

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

 

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

使用普通for循环遍历

代码如下:
[java] view plain copy
 
  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. }  

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

使用增强型for循环遍历

[java] view plain copy
 
  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. }  

结果如下:
增强for循环遍历
 
可以看到删除第一个元素时是没有问题的,但删除后继续执行遍历过程的话就会抛出ConcurrentModificationException的异常。
 

使用iterator遍历

[java] view plain copy
 
  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循环遍历
 
可以看到顺利的执行了遍历并删除的操作,因此最推荐的做法是使用iterator执行遍历删除操作。
 
以上是关于非线程安全的ArrayList,如果是线程安全的CopyOnWriteArrayList呢?
 

使用普通for循环遍历

 
[java] view plain copy
 
  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. }  

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

使用增强型for循环遍历

[java] view plain copy
 
  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. }  

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

使用iterator遍历

[java] view plain copy
 
  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. }  

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

 

分享到:
评论

相关推荐

    正确遍历删除List中的元素方法(推荐)

    下面小编就为大家带来一篇正确遍历删除List中的元素方法(推荐)。小编觉得挺不错的,在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Python中list循环遍历删除数据的正确方法

    前言 初学Python,遇到过这样的问题,在遍历list的时候,删除符合条件的数据,可是总是报异常,代码如下: ...原因是在删除list中的元素后,list的实际长度变小了,但是循环次数没有减少,依然按照

    解决Python 遍历字典时删除元素报异常的问题

    错误的代码① d = {'a':1, 'b':0, 'c':1, 'd':0} for key, val in d.items(): del(d[k]) 错误的代码② — 对于Python3 d = {'a':1, 'b':0, 'c':1, 'd':0} ...以上这篇解决Python 遍历字典时删除元素报异常的问

    对python list 遍历删除的正确方法详解

    在遍历list的时候,删除符合...原因是在删除list中的元素后,list的实际长度变小了,但是循环次数没有减少,依然按照原来list的长度进行遍历,所以会造成索引溢出。 解决方案:倒序循环删除 num_list = [1, 2, 3, 4,

    关于STL的erase()陷阱-迭代器失效问题的总结

    下面材料整理自Internet&...在使用 list、set 或 map遍历删除某些元素时可以这样使用: 1.1 正确写法1 std::list&lt; int&gt; List; std::list&lt; int&gt;::iterator itList; for( itList = List.begin(); itList != List.end();

    python_interview_question:关于python的面试题

    一行代码实现1-100之和21.Python-遍历列表时删除元素的正确做法22.字符串的操作题目23.可变类型和不可变类型24.is和==有什么区别?25.求出列表所有奇数并构造新列表26.用一行python代码写出1+2+3+1024827.Python中...

    flex3的cookbook书籍完整版dpf(包含目录)

    在State Changes事件中添加和删除事件监听器 11.11节. 添加视图States到Flash组件 11.12节. 处理StateChange 事件 11.13节. 动态生成States和Transitions 11.14节. 创建State的自定义动作(action) 第十二章. 特效...

    Python Cookbook

    5.9 在排序完毕的序列中寻找元素 199 5.10 选取序列中最小的第n个元素 200 5.11 三行代码的快速排序 203 5.12 检查序列的成员 206 5.13 寻找子序列 208 5.14 给字典类型增加排名功能 210 5.15 根据姓的首字母...

    用c描述的数据结构演示软件

    在演示算法之前,需先在弹出的小窗口中输入线性表的数据元素及算法参数 i(插入或删除的位置)和 b(被插的数据元素)的值。顺序表的图示窗口在演示屏的上方,链表的图示窗口在左侧。 2. 有序表的操作 算法演示屏的...

    数据结构演示软件

    在演示算法之前,需先在弹出的小窗口中输入线性表的数据元素及算法参数 i(插入或删除的位置)和 b(被插的数据元素)的值。顺序表的图示窗口在演示屏的上方,链表的图示窗口在左侧。 2. 有序表的操作 算法演示屏...

    net学习笔记及其他代码应用

    声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其...

    JAVA面试题最全集

    数据结构,如何遍历List中的元素? 如果要按照键值保存或者访问数据,使用什么数据结构? 要掌握Collection相关的接口和类的使用 56.使用StringBuffer类与String类进行字符串连接时有何区别? 57.调用Thread类的...

    Java开发实战1200例(第1卷).(清华出版.李钟尉.陈丹丹).part3

    本书是第II卷,以开发人员在项目开发中经常遇到的问题和必须掌握的技术为中心,介绍了应用Java进行桌面程序开发各个方面的知识和技巧,主要包括Java语法与面向对象技术、Java高级应用、窗体与控件应用、文件操作...

    java 面试题 总结

    栈是一种线形集合,其添加和删除元素的操作应在同一段完成。栈按照后进先出的方式进行处理。 堆是栈的一个组成元素 19、forward 和redirect的区别 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL...

Global site tag (gtag.js) - Google Analytics