参考:http://blog.csdn.net/longyulu/article/details/8315068

在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()方法。

  // 过滤掉空的热点天气
Iterator<HotWeather.HotInfo> iterator = hotInfos.iterator();
while (iterator.hasNext()) {
HotWeather.HotInfo item = iterator.next();
if (TextUtils.isEmpty(item.getTitle())) {
iterator.remove();
}
}

以下是JDK-API中对于remove()方法的描述:

void remove()

从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。每次调用 next 只能调用一次此方法。如果进行迭代时用调用此方法之外的其他方式修改了该迭代器所指向的集合,则迭代器的行为是不明确的。

抛出:UnsupportedOperationException - 如果迭代器不支持 remove 操作。IllegalStateException - 如果尚未调用 next 方法,或者在上一次调用 next 方法之后已经调用了remove 方法。

Java遍历List的时候删除item的更多相关文章

  1. java遍历Map时remove删除元素

    public class T { /** * @param args */ public static void main(String[] args) { // TODO Auto-generate ...

  2. 【Java】集合(List、Set)遍历、判断、删除元素时的小陷阱

    开发中,常有场景:遍历集合,依次判断是否符合条件,如符合条件则删除当前元素. 不知不觉中,有些陷阱,不知你有没有犯. 一.漏网之鱼-for循环递增下标方式遍历集合,并删除元素 如果你用for循环递增下 ...

  3. Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果

    本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/18311877) 今天还是给大家带来自定义控件的编写,自定义一个Lis ...

  4. Android 高级UI设计笔记03:使用ListView实现左右滑动删除Item

    1. 这里就是实现一个很简单的功能,使用ListView实现左右滑动删除Item: (1)当我们在ListView的某个Item,向左滑动显示一个删除按钮,用户点击按钮,即可以删除该项item,并且有 ...

  5. 【转】Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

    原文网址:http://blog.csdn.net/xiaanming/article/details/17539199 转帖请注明本文出自xiaanming的博客(http://blog.csdn. ...

  6. [转]Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

    转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17539199),请尊重他人的辛勤劳动成果,谢谢! 我在上一 ...

  7. STL中vector的赋值,遍历,查找,删除,自定义排序——sort,push_back,find,erase

    今天学习网络编程,那个程序中利用了STL中的sort,push_back,erase,自己没有接触过,今天学习一下,写了一个简单的学习程序.编译环境是VC6.0         这个程序使用了vect ...

  8. iOS遍历数组的同时删除元素

    我们在遍历可变数组时,最好不要做删除数组中元素的操作. 因为删除操作可能会引起数组容量的变化,导致数组越界等问题. 以前在使用for循环遍历的时候遇到过这个问题. 当时的做法是使用enumerateO ...

  9. Java ArrayList正确循环添加删除元素方法及分析

    在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体原因,本文就来深入分析一下该规定背后的思考. 一.foreach循环 foreach循环(Foreach loop)是计算机编程 ...

随机推荐

  1. 《Lua程序设计 第二版》学习笔记一

    Lua简介 Lua是一种简单.可拓展.可移植及高效的脚本语言. 开始 Lua之间不需要分隔符 运行方式: Linux下: lua -i prog dofile("lib1.lua" ...

  2. 对象的constructor属性

    对象的constructor属性, 最初是用来标识对象类型的. 比如 ,我们定义一个 Person类,然后实例化两个对象. function Person(name, age, job){this.n ...

  3. python 输入和输出

    到目前为止我们遇到过两种输出值的方法: 表达式语句和print语句. (第三个方式是使用文件对象的write()方法: 标准输出文件可以引用 sys.stdout.详细内容参见库参考手册. Pytho ...

  4. ajax 载入html后不能执行其中的js解决方法

    事件背景 有一个公用页面需要在多个页面调用,其中涉及到部分js已经写在了公用页面中,通过ajax加载该页面后无法执行其中的js. 解决思路 1. 采用附加一个iframe的方法去执行js,为我等代码洁 ...

  5. BZOJ 1461: 字符串的匹配

    Description 同上题. Sol KMP+树状数组. 写这题的时候我灰常naive...不管了...直接贴代码... Code /******************************* ...

  6. IDEA集成MAVEN 报错

      解决-Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment varia ...

  7. td的title属性

    今天才知道html元素td还有一个title属性,就是一个tooltip的东西,即当你把鼠标放在td上面的时候,会弹出一个提示语,这个提示语就是td的title. 把td的文本赋值给title: ht ...

  8. Python核心编程这本书的一些错误

    <Python核心编程第二版>这本书比<Python基础教程第二版修订版>详细很多,丰富了很多细节,虽然它是一本经典的入门书,但我发现还是存在一些明显的错误.在面向对象编程这一 ...

  9. 【GoLang】GoLang 官方 对 error 处理的意见

    The Go Blog Errors are values 12 January 2015 A common point of discussion among Go programmers, esp ...

  10. c里面的fflush函数

    NAME fflush - flush a stream SYNOPSIS #include <stdio.h> int fflush(FILE *stream); DESCRIPTION ...