用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作。
下面用List为例来说明为什么会报 ConcurrentModificationException 这个异常,其它集合类似可以自己思考。
public static void main(String[] args){
List<String> set = new ArrayList<String>();
set.add("a10001");
set.add("a10002");
set.add("a10003");
set.add("a10004");
set.add("a10005");
set.add("a10006");
set.add("a10007");
List<String> del = new ArrayList<String>();
del.add("a10003");
del.add("a10004");
del.add("a10005");
for(String str : set)
{
if(del.contains(str))
{
set.remove(str);
}
}
}
运行这段代码的结果
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at com.debug.Debug.main(Debug.java:28)
大家都知道for(String str : set) 这句话实际上是用到了集合的iterator() 方法
在iterator的时候是产生了一个List的内部类Itr
JDK源码
public Iterator<E> iterator() {
return new Itr();
}
在new Itr()时有一个关键性的操作
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
再回头看一下List 的 remove方法
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
再看一下 iterator.next()操作
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
相信看到这儿大家已经应该明白了为什么会出现在这个异常了。
总结:
iterator 时 将expectedModCount = modCount 在remove()时 modCount++ 在next()时
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
一旦删除或添加元素后 modCount ,expectedModCount 这两个值就会不一致 当next时就会报ConcurrentModificationException
了解了原由,解决方案就很简单了 在遍历时用一个集合存放要删除的对象 在遍历完后 调用removeAll(Collection<?> c) 就OK了。
分享到:
相关推荐
java.util.ConcurrentModificationException 异常问题详解1
java.util.ConcurrentModificationException 解决方法 在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。 则使用会报以下异常: Java.util....
主要介绍了出现java.util.ConcurrentModificationException 问题及解决办法的相关资料,需要的朋友可以参考下
Map在遍历时候通常 现获得其键值的集合Set,然后用迭代器Iterator来对Map进行遍历。
Spring数据mongodb测试 在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException
java.util.ConcurrentModificationException: mutation occurred during iteration [error] scala.collection.mutable.MutationTracker$.checkMutations(MutationTracker.scala:43) [error] scala.collection....
java中,List在遍历的时候,如果被修改了会抛出java.util.ConcurrentModificationException错误。 看如下代码: import java.util.ArrayList; import java.util.List; public class Resource3 { public ...
简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34.EJB规范规定EJB中禁止的操作有哪些? 35.java除了8种基本类型外,在虚拟机里还有哪一种,有什么作用? 36.除了使用new关键字创建对象意外,试列举...
JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...
超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...