遇到异常的代码段
for (Map.Entry<ImageView, UserConcise> peer : mPortraitViewPeers.entrySet()) {
ImageView key = peer.getKey();
key.setImageBitmap(peer.getValue().getProfile_image());
mPortraitViewPeers.remove(key);
}
在查看一些资料后,修改的代码
Iterator<Map.Entry<ImageView, UserConcise>> iterator = mPortraitViewPeers.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<ImageView, UserConcise> entry = iterator.next();
ImageView key = entry.getKey();
key.setImageBitmap(entry.getValue().getProfile_image());
iterator.remove();
}
以下是网上的解释
java.util.ConcurrentModificationException
工作中碰到个ConcurrentModificationException。代码如下:
List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj);
}
}
在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.ConcurrentModificationException(当然,如果remove的是最后一条,就不会再去执行next()操作了)
下面来看一下源码
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
boolean add(E o);
boolean remove(Object o);
...
}
这里有两个remove方法
接下来来看看AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//AbstractCollection和List都继承了Collection
protected transient int modCount = 0;
private class Itr implements Iterator<E> { //内部类Itr
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification(); //特别注意这个方法
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet); //执行remove对象的操作
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //重新设置了expectedModCount的值,避免了ConcurrentModificationException的产生
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //当expectedModCount和modCount不相等时,就抛出ConcurrentModificationException
throw new ConcurrentModificationException();
}
}
}
remove(Object o)在ArrayList中实现如下:
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++; //只增加了modCount
....
}
所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用remove()方法。
这里我们就不看add(Object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个List了
下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
分享到:
相关推荐
主要介绍了Java HashMap 如何正确遍历并删除元素的方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
可以通过2种方法遍历HashMap <br>Map map = new HashMap(); <br>for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { <br> Map.Entry entry = (Map.Entry) iter.next(); <br> Object ...
1、遍历Map.entrySet():它的每一个元素都是Map.Entry对象,这个对象中, 放着的就是Map中的某一对key-value; 2、遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来 读取Map中的元素; 3、...
在本篇文章中小编给大家分享了关于HashMap和List遍历方法及如何遍历删除元素知识点总结,需要的朋友们参考下。
哈希树遍历 HashMap遍历和使用 HashMap遍历和使用
HashMap 中元素的存储规则是按照 key 的 hash 值找到下标,然后判断该位置是否有元素,如果有就将尾节点的 Node 的 next 指向新的元素;如果没有就直接插入。 红黑树的插入操作: 在红黑树中,插入操作是通过 ...
主要介绍了Java5种遍历HashMap数据的写法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
讲述了hashmap的几种遍历方法,相当经典
看完这篇 HashMap,和面试官扯皮就没问题了 - HashMap 概述 - HashMap 和 HashTable 的区别 - 相同点 - 不同点 - HashMap 和 HashSet 的区别 ... - HashMap 中的移除方法 - 关于 HashMap 的面
动态扩容:当HashMap中的元素数量超过了容量(默认为16)与负载因子(默认为0.75)的乘积时,HashMap会自动扩容,即创建一个新的数组,并将原来的元素重新映射到新的数组中。 高性能:由于使用了哈希表,HashMap在查找...
下面小编就为大家带来一篇基于HashMap遍历和使用方法(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了java遍历HashMap简单的方法,以实例形式简单分析了采用java遍历HashMap的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
自己写的例子,关于HashSet遍历和HashMap遍历的. 感谢大家参考
遍历ArrayList存入HashMap中
3. 如果数组中的该索引处已经存在键值对,则循环遍历链表,直到找到相同的键值对。 4. 如果找到了相同的键值对,则将新值覆盖旧值,并返回旧值。 5. 如果没有找到相同的键值对,则将键值对添加到链表中。 Hash 码的...
该资源摘自: http://www.cnblogs.com/kristain/articles/2033566.html
当两个或更多的键的哈希值相同时,就会发生哈希冲突,此时,这些键值对就会存储在链表中。 在JDK1.8之前,当链表长度大于阈值(默认为8)时,链表会被转化为红黑树,以减少搜索时间。而在JDK1.8之后,这个阈值被改...
HashMap之往红黑树添加元素-putTreeVal方法源码解读:当要put的元素所在数组索引位置已存在元素,且是红黑树类型时,就会调用putTreeVal方法添加元素到红黑树上,具体操作步骤如下: 1. 从根节点开始,到左右子树,...
map接口是一个双边队列,拥有key,value两个属性,其中key在存储的集合中不允许重复,value可以重复。 HashMap特点 存储结构在jdk1.7当中是数组加链表的结构,在jdk1.8当中改为了数组加链表加红黑树的结构。 HashMap...
下面小编就为大家带来一篇使用多种方式实现遍历HashMap的方法。小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧