在遍历 Hashmap 时,Hashmap 在 remove() 和 put() 上的行为不同

Hashmap behaves differently upon remove() and put() while iterating through Hashmap

我试图更好地理解 hashmap,我研究了代码和可能性。当我想到这个时

//HashMap
Map<String, String> myMap = new HashMap<>();
myMap.put("1", "1");
myMap.put("2", "1");
myMap.put("3", "1");
System.out.println("HashMap before iterator: " + myMap);

for(String key : myMap.keySet()){
    if(key.equals("3")) {
        myMap.put(key + "new", "new3");
        myMap.remove("2");      
    }
};

for(String key : myMap.keySet()){
    if(key.equals("3")) {
        myMap.put(key + "new", "new3");
        break;  
    }
};
System.out.println("HashMap after iterator: " + myMap);

这个输出是

HashMap before iterator: {1=1, 2=1, 3=1}
HashMap after iterator: {1=1, 3=1, 3new=new3}

hashmap 中的迭代器是快速失败的,那么它如何适应这种变化。在此之后,我开始知道有一个计数器可以检查 hashmap 的大小,并在 next()[ 中大小不匹配时抛出异常=32=].

我不明白的是如何打破循环避免在正确的时刻调用 next() 以跳过检查。我什至看了迭代器HashIterator的代码 我不知道当代码命中 break;

时,hoe 不会调用 next()

为什么这段代码不会抛出错误。

        //HashMap
    HashMap<String, String> myMap = new HashMap<>();
    myMap.put("1", "1");
    myMap.put("2", "1");
    myMap.put("3", "1");
    System.out.println("HashMap before iterator: "+myMap);

    for(String key : myMap.keySet()){
        if(key.equals("3")) 
            myMap.remove("2");      
    };

    System.out.println("HashMap  after iterator: " + myMap);

    for(String key : myMap.keySet()){
        if(key.equals("3")) 
            myMap.put(key + "new", "new3");
    };

    System.out.println("HashMap  after iterator: " + myMap);

请帮助我更好地理解这一点。

嗯,HashIterator 检查 next() 中的 modCount,但不检查 hasNext() 中的 modCount

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

    final Node<K,V> nextNode() {
        Node<K,V>[] t;
        Node<K,V> e = next;
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        if ((next = (current = e).next) == null && (t = table) != null) {
            do {} while (index < t.length && (next = t[index++]) == null);
        }
        return e;
    }

由于您要在循环的最后一次迭代中对 HashMap 进行结构更改,因此更改 hasNext() returns falsenext() 不再调用。因此也不例外。

请注意,由增强的 for 循环创建的迭代器并不知道您向 Map 添加了一个额外的 Entry。因此它不会迭代那个额外的 Entry。快速失败机制只有在迭代器的 next() 方法被调用时才能工作,但如前所述,当您在循环的最后一次迭代中进行更改时不会发生这种情况。