java foreach循环中调用remove 抛出java.util.ConcurrentModificationException

来源:互联网 发布:网页代码编写软件 编辑:程序博客网 时间:2024/06/11 09:41

这是一个快速失败的非典型例子。

for (String str : list) {if("".equals(str)){list.remove(str);}}

因为使用foreach的语法,进行循环,实际上是使用了Iterator进行迭代,使用Iterator进行迭代的同时,移除了其中的对象,破坏了Iterator内部用来迭代的索引。所以抛出异常。用for循环就不会。

深入解析:

1、Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象[1],所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。

2、用for循环也不合理,查ArrayList的源码,执行remove时,会把当前索引后面的数据往前移一位,再把最后一位赋为null,这就导致最后有些元素遍历不到。


解决办法举例:

1、倒过来遍历

2、每删除一个,执行一次i--

3、使用iterator.remove()

 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。


附注[1]:当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象[1],这句没看懂,我的理解是假如移除一个,那么list的实际大小为size--,迭代器索引的大小为size,那么最后index=size-1时会报错,但是发现当移除第size/2个元素时,size/2+1就报错了。

0 0