在迭代Hashmap时,Hashmap对remove()和put()的行为有所不同

时间:2018-04-23 06:48:01

标签: java hashmap concurrenthashmap

我试图更好地理解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() 中的大小不匹配时抛出异常

我没有得到的是如何打破循环,避免在正确的时刻调用next()来跳过检查。我甚至查看了迭代器HashIterator的代码 当代码命中 break;

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

        //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);

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

1 个答案:

答案 0 :(得分:2)

好吧,HashIterator检查modCount中的next(),但未在hasNext()中检查:

    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()会返回false并且不会再次调用next()。因此也不例外。

请注意,增强型for循环创建的迭代器不会意识到您向Entry添加了额外的Map这一事实。因此,它不会迭代额外的Entry。快速失效机制只有在调用迭代器的next()方法时才能工作,但正如前面所解释的那样,当你在循环的最后一次迭代中进行更改时,这种情况不会发生。 / p>