Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/kubernetes/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
知道为什么在从HashMap中删除密钥时没有得到java.util.ConcurrentModificationException吗?_Java_Hashmap_Concurrentmodification - Fatal编程技术网

知道为什么在从HashMap中删除密钥时没有得到java.util.ConcurrentModificationException吗?

知道为什么在从HashMap中删除密钥时没有得到java.util.ConcurrentModificationException吗?,java,hashmap,concurrentmodification,Java,Hashmap,Concurrentmodification,我想实现的是,如果key是要删除的key,则将key更改为current time,但其值应该相同 我的代码片段是: public class hello { private static HashMap<String,String> fileMap; private static final String KEY_REMOVED = "d"; static { fileMap = new HashMap<String, String&g

我想实现的是,如果key是要删除的key,则将key更改为current time,但其值应该相同

我的代码片段是:

public class hello
{
    private static HashMap<String,String> fileMap;
    private static final String KEY_REMOVED = "d";
    static {
        fileMap = new HashMap<String, String>();
        fileMap.put("a", "hello");
        fileMap.put(KEY_REMOVED, "bye");
        fileMap.put("c", "hi");
    }

    public static void main(String []args){
        upload();
}

    private static void upload() throws  ConcurrentModificationException {

        for (Map.Entry<String, String> entry : fileMap.entrySet()) {
            System.out.println("Uploading key " + entry.getKey());

            String fileName = entry.getKey();

            if (fileName.equals(KEY_REMOVED)) {
                fileName = new Timestamp(System.currentTimeMillis()).getTime();
                String temp2 = fileMap.remove(VIDEO_MP4_ASSET);
                System.out.println("hashmap after removing key is " + fileMap);
                System.out.println("adding  key to hashmap " + fileName);
                fileMap.put(fileName, temp2);

            } else {

                System.out.println("continue");
            }
            System.out.println("hashmap is " + fileMap);
        }
    }

理想情况下,在删除密钥时,我们应该得到ConcurrentModificationException。我担心我现在没有得到它。但我的代码可能稍后会中断。是吗?

迭代器不需要检测任何并发修改并引发异常。事实上,在任意并发修改上保证并发修改异常是相当困难的。您永远不应该依赖于抛出此异常

在您的示例中,如果您想保证不会发生并发修改,那么需要为迭代创建entryset的临时副本。最好的办法是换线

    for (Map.Entry<String, String> entry : fileMap.entrySet()) {


这可能有点混乱,因为Javadoc首先声明

该类的所有集合视图返回的迭代器 方法值、键集、入口集是快速失败的:如果 在使用迭代器之后,可以随时修改map的结构 以任何方式创建,除了通过迭代器自己的remove方法, 迭代器将抛出ConcurrentModificationException

请注意,无法保证迭代器的快速失败行为

但它也指出

返回此映射中包含的映射的集合视图。布景是 由地图支持,因此地图的更改将反映在集合中,并且 反之亦然。如果在集合上进行迭代时修改贴图 正在进行,但通过迭代器自己的删除操作除外,或 通过对 迭代器迭代的结果未定义

现在undefined确实包括抛出ConcurrentModificationException,但也有一些地方没有抛出它,因为正如一开始所看到的,fail fast行为无法得到保证


因此,如果您在对键集、值或入口集进行迭代,并且在结构上修改映射,即使用新键移除或放置,而不是替换现有键的值,那么您可能会得到:ConcurrentModificationException或在迭代过程中发生的奇怪事情,例如跳过元素或两次遇到一个元素。

ConcurrentModificationException并不是一种安全的方法,它不能像关于HashMap的文档所说的那样,知道您的集合是否发生了变化: 请注意,无法保证迭代器的快速失效行为,因为一般来说,在存在非同步并发修改的情况下,不可能做出任何硬保证。快速失败迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测bug

如果要确保没有人更改您的集合,可以使用同步版本的HashMap:


Map m=Collections.synchronizedMapnew HashMap

这是在迭代时重命名hashmap中的键的正确方法吗

将值存储在temp变量中,删除键并使用新键和temp放入新条目

Iterator<Map.Entry<String,String>> iter = fileMap.entrySet().iterator();
while (iter.hasNext()) { 

Map.Entry<String, String> entry = iter.next(); 
fileName = entry.getKey(); 

if (fileName.equals(KEY_REMOVED)) {
fileName = new Timestamp(System.currentTimeMillis()).getTime(); 
String temp = entry.getValue(); 
iter.remove(); 
System.out.println("hashmap after removing key is " + fileMap); 
fileMap.put(fileName, temp); 
System.out.println("Updated hashmap after addng key is " + fileMap); 
} 
else
{
 System.out.println("continue");
}
}

如果正在循环数组,则不能同时对该数组执行操作。您应该创建另一个数组,该数组存储要删除的所有内容的列表,然后在完成循环后删除它们。@R10t-您不能以任何方式从数组中删除元素。通常,只要显式使用迭代器,就可以遍历集合并删除项;还有很多其他看似随机的东西,包括:删除了System.out.printlnholl World;这代码不是在HashMap上迭代,而是在一组Map.Entry上迭代。那么,在相同的迭代中实现移除和放置的正确方法是什么?或者更改键但保持相同的值?或者在迭代时重命名hashmap中的键?@Darspreetnarula没有合适的方法,您通常希望完全避免这种设计。但是作为一种解决方法,您可以在存储更改的位置添加和删除两个附加的帮助器映射,然后在迭代之后对映射进行修改。或者,您可以告诉自己正在尝试做什么,以便提出更好的设计。Collections.synchronizedMap不会阻止ConcurrentModificationException。在本例中,并发字与多线程无关。感谢@kayaman的澄清,我对文档中使用并发字感到困惑。如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改映射,则必须在外部同步。
Iterator<Map.Entry<String,String>> iter = fileMap.entrySet().iterator();
while (iter.hasNext()) { 

Map.Entry<String, String> entry = iter.next(); 
fileName = entry.getKey(); 

if (fileName.equals(KEY_REMOVED)) {
fileName = new Timestamp(System.currentTimeMillis()).getTime(); 
String temp = entry.getValue(); 
iter.remove(); 
System.out.println("hashmap after removing key is " + fileMap); 
fileMap.put(fileName, temp); 
System.out.println("Updated hashmap after addng key is " + fileMap); 
} 
else
{
 System.out.println("continue");
}
}