集合遍历的时候删除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 方法。

时间: 2025-01-01 20:46:21

集合遍历的时候删除List的相关文章

java 集合遍历时删除元素

本文探讨集合在遍历时删除其中元素的一些注意事项,代码如下 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 import java.util.ArrayList; import java.util.Iterator; import java

Java集合遍历时删除

public static void main(String[] args){ List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); Iterator<Integer> interator = list.iterator(); while(interator.hasNext()){ Integer i

java集合遍历删除指定元素异常分析总结

在使用集合的过程中,我们经常会有遍历集合元素,删除指定的元素的需求,而对于这种需求我们往往使用会犯些小错误,导致程序抛异常或者与预期结果不对,本人很早之前就遇到过这个坑,当时没注意总结,结果前段时间又遇到了这个问题,因此,总结下遍历集合的同时如何删除集合中指定的元素: 1.错误场景复原 public class ListRemoveTest { public static void main(String[] args) { List<User> users = new ArrayList&l

集合遍历

set集合遍历: 1.迭代器 2.增强for循环:只能遍历 List集合的遍历: 1. 迭代器 2. 增强for循环 3. 普通for循环 get(index) 和size() 注:增强for循环:只能遍历,不能删除,迭代器遍历可以删除,但必须使用迭代器,普通for循环可以删除,但必须记得i--;

Java集合遍历性能

数据在内存中主要有两种存储方式: 1.顺序存储,Random Access(Direct Access) 这种方式,相邻的数据元素存放于相邻的内存地址中,整块内存地址是连续的,可以根据元素的位置直接计算出内存地址,直接进行读取.读取一个特定位置元素的平均时间复杂度为O(1).正常来说,只有基于数组实现的集合,才有这种特性.Java中以ArrayList为代表. 2.链式存储,Sequential Access: 这种方式,每一个数据元素,在内存中都不要求处于相邻的位置,每个数据元素包含他的下一个

iOSDay16之集合遍历和数组排序

1.集合遍历 1> 遍历 集合(Collection):OC中提供的容器类:数组,字典,集合. 遍历:对集合中元素依次取出的过称叫做遍历. 三种方式:① for循环遍历: ② NSEnumerator遍历: ③ for...in遍历 2> for循环遍历 ① 数组遍历 原理:通过for循环的循环变量用作数组元素下标来获取不同下标的元素. 循环次数就是数组元素的个数. 1 // 数组 2 for (int i = 0; i < arr.count; i++) { 3 NSLog(@&quo

C#遍历List并删除某个元素的方法

C#遍历List并删除某个元素的方法,你的第一反应使用什么方法实现呢?foreach? for? 如果是foreach,那么恭喜你,你答错了.如果你想到的是用for,那么你只是离成功进了一步. 正确的做法是用for倒序遍历,根据条件删除.下面我们用代码来演示foreach,for删除list数据的情况: class Program { public class Students { public string Name { get; set; } public int Age { get; se

集合遍历的几种方式

集合遍历有几种方式,下面是我总结的. 1     增强for循环:foreach       语法: for(类型 变量:集合名){  } 这是上名代码的结果 集合: 非单个数据的存储:     Iterator it = 集合对象.iterator();     调用对象自己的iterator() 创建属于这个对象自己的迭代器,然后把迭代器赋值给迭代器的父类     多态:迭代器进行向上转型     就是父类的引用指向子类的对象         向上转型 向下转型       Iterator

C#遍历List并删除某个或者几个元素的方法

C#遍历List并删除某个或者几个元素的方法,你的第一反应使用什么方法实现呢?foreach? for? 如果是foreach,那么恭喜你,你答错了.如果你想到的是用for,那么你只是离成功进了一步. 正确的做法是用for倒序遍历,根据条件删除.下面我们用代码来演示foreach,for删除list数据的情况: class Program { public class Students { public string Name { get; set; } public int Age { get