for each删除List中的元素出错

转载 2016年08月31日 13:42:48

场景是,需要删除objList中的某几个元素,自然而然,我们会习惯性的写下如下语句:
int i = 0;  
for(Object o : objList)  
{  
    if(o == value)  
   {  
       objList.remove(i);   
   }  
   i++;  
}  
报错:
这时你就会发现报 java.util.ConcurrentModificationException 异常,此异常是迭代器抛出的异常,官方说明是:
The Iterators returned by this class’s iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
大概意思是:在用迭代器迭代集合的时候,迭代器一旦创建,就不允许更改集合,如果所迭代的集合(Set或者List)的有修改的话,就会抛出 
ConcurrentModificationException异常, 用迭代器自身的remove方法除外…
原理:

用for-each遍历 实际上使用的是Iterator迭代器 

Iterator的工作机制: 

Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。
List、Set等是动态的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,如果逆向读取,需要重写iterator(),当 Iterator指向的原始数据发生变化时,Iterator自己就迷失了方向。
解决方法:
删除指定的元素应该如何呢?
一. 用一个List 记录要删除的数据,最后removeAll(List);
List<Integer> removeList = new ArrayList()  
for(Integer i : intList)  
{  
    if(i == 13)  
    {  
        removeList.add(i);  
    }  
}  
//最后  
if(removeList.size()>0)  
{  
    intList.removeAll(removeList);  
}
二.用for循环遍历,原始书写方式
for(int i = 0; i < intList.size(); i++)  
{  
    if(intList.get(i) == 13)  
    {  
        intList.remove(i);  
        //此时要注意,因为list会动态变化不像数组会占位,所以当前索引应该后退一位  
        i--;  
    }  
}
三.用迭代器自带的remove方法,这也是官方推荐的方法
Iterator <Integer> it = intList.iterator();  
while(it.hasNext())  
{  
    if(it.next() == 13)  
    {  
        it.remove();  
    }  
}

Java Iterator和增强for循环 for each详解

Iterator是Java中的一个迭代器接口(Interface),用来提供标准的Java迭代器 Iterator支持泛型因为集合(Collection)类可以装入的类型是不确定的,从集合中取出的都...
  • shf4715
  • shf4715
  • 2015年07月23日 21:30
  • 2924

for循环删除(ArrayList.remove)报错及解决办法

[java]   List list = new ArrayList();   list.add(1);   list.add(2);   list.add(3);   ...
  • u010523770
  • u010523770
  • 2016年07月18日 17:26
  • 6467

Java 基础集合遍历删除 for与foreach区别

在日常Java 开发中,想要在遍历中删除一个集合中的元素,这是很常见的,但是如果用法不当,那么就会导致系统存在一些隐式bug ! 笔者今天拿list 举例来分析一下,Java 中集合应如何正确删除. ...
  • xianglin2111
  • xianglin2111
  • 2018年01月13日 15:41
  • 26

for-each的背后

参考文章:Java for-each循环解惑
  • u011063151
  • u011063151
  • 2016年09月13日 20:24
  • 394

java for-each本质--不能增加和删除,但是可以修改当前元素

java for-each本质--不能增加和删除,但是可以修改当前元素
  • Enable1234___
  • Enable1234___
  • 2016年12月21日 22:35
  • 978

集合类的remove(obj)和iterator的remove方法差别

java.util.ConcurrentModificationException 工作中碰到个ConcurrentModificationException。代码如下: List list = .....
  • xad707348125
  • xad707348125
  • 2015年04月16日 15:31
  • 1873

Java 基础 之 集合遍历删除

在日常java 开发中,想要在遍历中删除一个集合中的元素,这是很常见的,但是如果用法不当,那么就会导致系统存在一些隐式bug ! 笔者今天拿list 举例来分析一下,Java 中集合应如何正确删除. ...
  • zgf19930504
  • zgf19930504
  • 2016年08月07日 09:55
  • 823

遍历Linux kernel的链表时删除节点的方法 list_for_each_safe

如果在遍历链表的时候需要删除当前节点,应该使用的遍历函数为:list_for_each_safe(pos, n, head)          内核的链表list_head设计相当巧妙。今天...
  • angle_birds
  • angle_birds
  • 2013年02月27日 15:57
  • 3114

为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法

最近在看《数据结构与算法分析》(Java语言描述)一书,看到第3.3.2 这一节时介绍Iterator接口。书中说道,“Iterator接口中包含一个方法,叫做remove()。该方法可以删除next...
  • u013096088
  • u013096088
  • 2016年06月26日 22:42
  • 1311

Iterator的remove方法可保证从源集合中安全地删除对象

如果对正在被迭代的集合进行结构上的改变(即对该集合使用add、remove或clear方法),那么迭代器就不再合法(并且在其后使用该迭代器将会有ConcurrentModificationExcept...
  • hustwht
  • hustwht
  • 2016年08月11日 13:34
  • 3350
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:for each删除List中的元素出错
举报原因:
原因补充:

(最多只允许输入30个字)