为什么迭代器不抛出并发修改异常?

why iterator is not throwing concurrentmodification exception?

为什么这个方法不抛出并发修改? 如果 if(next.equals("3") 它没有。但是,我将它更改为 equals("1") 它确实如此。这里发生了什么?

    private void checkConcurrentModification(){

        Map<String, Integer> map = new HashMap<>();

        map.put("1", 1);
        map.put("2", 2);
        map.put("3", 3);


        Iterator<Entry<String, Integer>> iterator = map.entrySet().iterator();

        while(iterator.hasNext()){
            String next = iterator.next().getKey();
            map.put(next, 1);
            if(next.equals("3")){ //does not throw exception
 //if(next.equals("1")){ //throws exception
                map.put("4", 4);
            }
        }

        for(Entry<String, Integer> entry : map.entrySet()){
            System.out.println("entry key and value" +entry.getKey() + " : " +entry.getValue());
        }

    }


prints:
entry key and value1 : 1
entry key and value2 : 1
entry key and value3 : 1
entry key and value4 : 4

这取决于 HashMap 的实施。

如果你 运行 在 Java 7 下,那么对于 if (next.equals("3")) 它将抛出一个 ConcurrentModificationException,而对于 1,它不会' t.

如果你 运行 在 Java 8 下,那么 3 不会抛出异常,而 1 会抛出异常。

原因是当您在 Java 7 下迭代映射时,第一个键将是 3,最后一个是 1。所以你在修改值的同时还有其他值要迭代。

在Java 8下,迭代中的第一个键是1,最后一个是3

如果您在遇到最后一个键时修改地图,它不会检查该修改,因为它只会在您下次尝试调用 next() 时检查它,但在最后一个值之后,hasNext() returns false,所以不调用next(),避免了异常。

在循环内更改地图后尝试访问 iterator.next().getKey(); 之前,不会抛出 ConcurrentModificationException。在示例中 "3" 是原始映射中的最后一个键,并且在抛出异常之前退出循环。对于原始映射中除最后一个键之外的每个键,都会抛出异常。

ConcurrentModificationException 当迭代器到达下一个地图键时抛出,如果您在上一步中向地图添加了新键。因此,如果您测试的键不是地图中的最后一个键,您只会得到异常。在你的情况下 3 肯定是最后一个。

注意:由于 HashMap 没有顺序,在一台机器上 3 可能是最后一个,在其他机器上 12 可能是最后一个。