java - 即使使用 iterator.remove() 删除节点,HashMap 也会抛出 ConcurrentModification

标签 java android hashmap

我在操作 HashMap 时遇到了 ConcurrentModificationException。代码如下:

    Iterator<Integer> iterator =cacheMap.keySet().iterator();
        while(iterator.hasNext()) {
        if(iterator.next() == target) {
            iterator.remove();
        }
    }

我使用的唯一操作是那样删除和 cacheMap.put(node)。并且这些方法都是在主线程中调用的,包括ActivityonCreate()方法,AsyncTask<的onPostExecute()方法handleMessage(Message msg) 方法在主线程的处理程序中。

但是偶尔会在iterator.next()中使用上面的方法移除节点时抛出ConcurrentModificationException,虽然这种情况真的很少。

我查阅了HashMap中的相关方法。是这样的:

@Override public Set<K> keySet() {
    Set<K> ks = keySet;
    return (ks != null) ? ks : (keySet = new KeySet());
}

private final class KeyIterator extends HashIterator
        implements Iterator<K> {
    public K next() { return nextEntry().key; }
}

private abstract class HashIterator {
    int nextIndex;
    HashMapEntry<K, V> nextEntry = entryForNullKey;
    HashMapEntry<K, V> lastEntryReturned;
    int expectedModCount = modCount;

    HashIterator() {
        if (nextEntry == null) {
            HashMapEntry<K, V>[] tab = table;
            HashMapEntry<K, V> next = null;
            while (next == null && nextIndex < tab.length) {
                next = tab[nextIndex++];
            }
            nextEntry = next;
        }
    }

    public boolean hasNext() {
        return nextEntry != null;
    }

    HashMapEntry<K, V> nextEntry() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (nextEntry == null)
            throw new NoSuchElementException();

        HashMapEntry<K, V> entryToReturn = nextEntry;
        HashMapEntry<K, V>[] tab = table;
        HashMapEntry<K, V> next = entryToReturn.next;
        while (next == null && nextIndex < tab.length) {
            next = tab[nextIndex++];
        }
        nextEntry = next;
        return lastEntryReturned = entryToReturn;
    }

    public void remove() {
        if (lastEntryReturned == null)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        HashMap.this.remove(lastEntryReturned.key);
        lastEntryReturned = null;
        expectedModCount = modCount;
    }
}

@Override public V remove(Object key) {
    if (key == null) {
        return removeNullKey();
    }
    int hash = secondaryHash(key);
    HashMapEntry<K, V>[] tab = table;
    int index = hash & (tab.length - 1);
    for (HashMapEntry<K, V> e = tab[index], prev = null;
            e != null; prev = e, e = e.next) {
        if (e.hash == hash && key.equals(e.key)) {
            if (prev == null) {
                tab[index] = e.next;
            } else {
                prev.next = e.next;
            }
            modCount++;
            size--;
            postRemove(e);
            return e.value;
        }
    }
    return null;
}

private V removeNullKey() {
    HashMapEntry<K, V> e = entryForNullKey;
    if (e == null) {
        return null;
    }
    entryForNullKey = null;
    modCount++;
    size--;
    postRemove(e);
    return e.value;
}

/**
 * Subclass overrides this method to unlink entry.
 */
void postRemove(HashMapEntry<K, V> e) { }

modCountexpectedModeCount 在调用 nextEntry()remove 时被检查。但是如果调用iterator.remove() 来删除节点,这两个整数的差异似乎是不可能的。

最佳答案

只需使用 cacheMap.remove(target)。

来自文档:

public V 删除(对象键) 从此映射中删除指定键的映射(如果存在)。

请记住,HashMap 只能为给定键存储一个对象,因此无需遍历所有值。

关于java - 即使使用 iterator.remove() 删除节点,HashMap 也会抛出 ConcurrentModification,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27143444/

相关文章:

java - Swing 事件未向上传递到基础组件

java - Android 文件未在 SD 卡上创建

java - 使用 retrofit 和 rxjava 重复调用 API

java.util.HashMap----看控制台,为什么打印顺序是这样的

algorithm - 在 O(logN) 时间复杂度中使用 HashMap 对节点链表进行二进制搜索

java - 当鼠标悬停在JavaFX中的按钮上时如何创建节点(圆形)?

Java字符串比较与正则表达式的区别?

java Runtime.getRuntime().exec 无法获取某些命令的输出

android - Android 上的 OpenCV 和 JavaCv - 检测图像上的形状

java - 允许分别提供相等比较器和散列函数的映射