集合遍历的时候删除List
在Java中有时候我们会需要对List里面的符合某种业务的数据进行删除,但是如果不了解里面的机制就容易掉入“陷阱”导致遗漏或者程序异常。本文以代码例子的方式进行说明该问题。
1、采用索引下标遍历的方式
我们看这段示例代码:
1 public class ListRemoveTest {
2
3 public static void main(String[] args) {
4 List<Integer> list = new ArrayList<Integer>();
5 list.add(1);
6 list.add(2);
7 list.add(2);
8 list.add(3);
9 list.add(4);
10
11 for (int i = 0; i < list.size(); i++) {
12 if (2 == list.get(i)) {
13 list.remove(i);
14 }
15 System.out.println(list.get(i));
16 }
17 System.out.println("最后结果=" + list.toString());
18 }
19 }
该代码运行结果如下:
1
2
3
4
最后结果=[1, 2, 3, 4]
我们是想删除等于2的元素,但结果显示只删除了一个2,另一个2被遗漏了,原因是:删除了第一个2后,集合里的元素个数减1,后面的元素往前移了1位,导致了第二个2被遗漏了。
2、采用For循环遍历的方式
1 public class ListRemoveTest {
2
3 public static void main(String[] args) {
4 List<Integer> list = new ArrayList<Integer>();
5 list.add(1);
6 list.add(2);
7 list.add(2);
8 list.add(3);
9 list.add(4);
10
11 for (Integer value : list) {
12 if (2 == value) {
13 list.remove(value);
14 }
15 System.out.println(value);
16 }
17 System.out.println("最后结果=" + list.toString());
18 }
19 }
程序运行结果:
1
2
Exception in thread “main” java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at ListRemoveTest.main(ListRemoveTest.java:32)
从运行结果看到程序抛ConcurrentModificationException。
JDK的API中对该异常描述道:
public class ConcurrentModificationException extends RuntimeException当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。
注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。
Java中的For each实际上使用的是iterator进行处理的。而iterator是不允许集合在iterator使用期间删除的。所以导致了iterator抛出了ConcurrentModificationException 。
3、在遍历List过程中删除元素的正确做法
1 public class ListRemoveTest {
2
3 public static void main(String[] args) {
4 List<Integer> list = new ArrayList<Integer>();
5 list.add(1);
6 list.add(2);
7 list.add(2);
8 list.add(3);
9 list.add(4);
10
11 Iterator<Integer> it = list.iterator();
12 while (it.hasNext()) {
13 Integer value = it.next();
14 if (2 == value) {
15 it.remove();
16 }
17 System.out.println(value);
18 }
19 System.out.println("最后结果=" + list.toString());
20 }
21 }
输出结果:
1
2
2
3
4
最后结果=[1, 3, 4]
我们看到两个2全部被删除了,最后结果剩下1,3,4完全正确。
但对于iterator的remove()方法,也有需要我们注意的地方:
1、每调用一次iterator.next()方法,只能调用一次remove()方法。
2、调用remove()方法前,必须调用过一次next()方法。
以下是JDK-API中对于remove()方法的描述:
void remove()
从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的集合,则迭代器的行为是不明确的。
抛出:
UnsupportedOperationException- 如果迭代器不支持 remove 操作。IllegalStateException- 如果尚未调用 next 方法,或者在上一次调用 next 方法之后已经调用了remove 方法。
集合遍历的时候删除List的更多相关文章
- list,set等集合遍历时,不能remove集合中的元素。需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAll(list/set)操作
list,set等集合遍历时,不能remove集合中的元素.需要new一个Object或者list,set,里面add需要删除的元素,等集合遍历完了进行remove(Object)或者removeAl ...
- java集合遍历删除指定元素异常分析总结
在使用集合的过程中,我们经常会有遍历集合元素,删除指定的元素的需求,而对于这种需求我们往往使用会犯些小错误,导致程序抛异常或者与预期结果不对,本人很早之前就遇到过这个坑,当时没注意总结,结果前段时间又 ...
- java list集合遍历时删除元素
转: java list集合遍历时删除元素 大家可能都遇到过,在vector或arraylist的迭代遍历过程中同时进行修改,会抛出异常java.util.ConcurrentModification ...
- iOS学习16之OC集合遍历和数组排序
1.集合遍历 1> 遍历 集合(Collection):OC中提供的容器类:数组,字典,集合. 遍历:对集合中元素依次取出的过称叫做遍历. 三种方式:① for循环遍历: ② NSEnumera ...
- OC中几种集合的遍历方法(数组遍历,字典遍历,集合遍历)
// 先分别初始化数组.字典和集合,然后分别用for循环.NSEnumerator枚举器和forin循环这三个方法来实现遍历 NSArray *array = @[@"yinhao" ...
- C#遍历List并删除某个或者几个元素的方法
C#遍历List并删除某个或者几个元素的方法,你的第一反应使用什么方法实现呢?foreach? for? 如果是foreach,那么恭喜你,你答错了.如果你想到的是用for,那么你只是离成功进了一步. ...
- iOS学习之Object-C语言集合遍历和数组排序
一.集合遍历 1.集合:OC中提供的容器类,数组,字典,集合. 2.遍历:对集合中元素依次取出的过程叫做遍历. 二.for循环遍历 1.通过for循环的循环变量用作数组元 ...
- python 遍历list并删除部分元素
python 遍历list并删除部分元素https://blog.csdn.net/afgasdg/article/details/82844403有两个list,list_1 为0-9,list_2 ...
- Java集合——遍历集合元素并修改
Java集合——遍历集合元素并修改 摘要:本文主要总结了遍历集合的方式,以及在遍历时修改集合要注意的问题. 遍历Collection 对List和Set的遍历,有四种方式,下面以ArrayList为例 ...
随机推荐
- mysqli 实例
1.封装数据库连接(connect.php): <?php // 封装数据库连接 // 设置页面编码声明 header("Content-type: text/html; charse ...
- Flex开发实战(一)--Flex的具体介绍
背景 因为近期要维护公司的项目,项目里面用到了Flex技术,所以近期一直在恶补.这篇博文就将近期的学习内容,进行一下简单的总结. 不管是做web还是桌面应用.相信大家对于界面的要求已经越来越高.界面趋 ...
- MongoDB笔记(二):MongoDB下Shell的基本操作
一.mongoDB与关系型数据库对比 对比项 mongoDB 关系型数据库(oracle.mysql) 表 集合List 二维表table 表的一行数 ...
- mysql Connector C++ 操作数据库 vs2012
最近想写一个应用程序,要连接和操作mysql数据库,以前只是用c++ builder 操作过mysql数据库,那是用控件操作的,感觉比较弱智,但是c++ builder vcl控件感觉在多线程里比较坑 ...
- mac下安装python pip、pyspider
如果mac下没有安装wget,还需要安装wget,见http://www.cnblogs.com/cocowool/archive/2012/06/24/2560574.html 使用 pip 安装 ...
- 【MyBatis学习14】MyBatis和Spring整合
前面十几篇博文总结了mybatis在开发中的相关技术,但在实际中都是和spring整合开发的,所以这里总结一下mybatis和spring的整合方法,并在整合后进行测试. 1. 整合的环境 这都是老掉 ...
- Android内存优化大全(中)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 写在最前: 本文的思路主要借鉴了2014年AnDevCon开发者大会的一个演讲PPT,加上 ...
- RHEL 5.4下部署LVS(DR)+keepalived实现高性能高可用负载均衡(转)
一.简介 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一. ...
- 自己动手开发更好用的markdown编辑器-04(实时预览)
这里文章都是从个人的github博客直接复制过来的,排版可能有点乱. 原始地址 http://benq.im/2015/04/25/hexomd-04/ 程序打包 文章目录 1. 打开新窗口 ...
- SRIO调试(C6678->SRIO和Virtex6->FPGA)
C6678->SRIO和Virtex6->FPGA 设计的板子到了SRIO调试阶段了,在板子上,一片V6和两片6678通过4XSRIO互联,中间没有Switch,总算搞定了相互之间的通 ...