Java 在地图上进行迭代时,允许对地图执行哪些基本操作?

Java 在地图上进行迭代时,允许对地图执行哪些基本操作?,java,iterator,Java,Iterator,假设我在Java中迭代地图。。。在迭代过程中,我不清楚我能对该地图做些什么。我想我对Javadoc中关于迭代器接口删除方法的警告感到困惑: […]如果在迭代过程中以调用此方法以外的任何方式修改了基础集合,则迭代器的行为是未指定的 我确信我可以毫无问题地调用remove方法。但是,在迭代地图集合时,我可以: 使用Map类put方法更改与键关联的值(使用现有键进行put) 使用Map类put方法添加一个新条目(使用新键放置) 是否使用Map类Remove方法删除条目 我的猜测是,我可能可以安全地执行

假设我在Java中迭代地图。。。在迭代过程中,我不清楚我能对该地图做些什么。我想我对Javadoc中关于迭代器接口删除方法的警告感到困惑:

[…]如果在迭代过程中以调用此方法以外的任何方式修改了基础集合,则迭代器的行为是未指定的

我确信我可以毫无问题地调用remove方法。但是,在迭代地图集合时,我可以:

  • 使用Map类put方法更改与键关联的值(使用现有键进行put)

  • 使用Map类put方法添加一个新条目(使用新键放置)

  • 是否使用Map类Remove方法删除条目

  • 我的猜测是,我可能可以安全地执行#1(放入现有密钥),但不安全地执行#2或#3


    提前感谢您对此所做的任何澄清。

    一般来说,如果您想在迭代地图时更改地图,您应该使用迭代器的方法之一。我实际上还没有测试过#1是否有效,但其他的肯定不会

    如果您查看HashMap类,您将看到一个名为“modCount”的字段。这就是映射如何知道在迭代过程中何时对其进行了修改。任何在迭代时增加modCount的方法都会导致它抛出ConcurrentModificationException

    也就是说,如果密钥已经存在,您可以将值放入映射中,从而有效地使用新值更新条目:

     Map<String, Object> test = new HashMap<String, Object>();
     test.put("test", 1);
    
     for(String key : test.keySet())
     {
         test.put(key, 2); // this works!
     }
    
     System.out.println(test); // will print "test->2"
    
    Map test=newhashmap();
    测试。放置(“测试”,1);
    for(字符串键:test.keySet())
    {
    test.put(键,2);//这很有效!
    }
    系统输出打印LN(测试);//将打印“测试->2”
    

    当您询问是否可以“安全地”执行这些操作时,您不必太担心,因为HashMap设计用于在遇到类似问题时立即抛出ConcurrentModificationException。这些行动很快就会失败;它们不会使映射处于错误状态。

    您可以使用
    迭代器.remove()
    ,如果使用entrySet迭代器(属于map.Entry),则可以使用
    map.Entry.setValue()
    。其他任何事情和所有赌注都是无效的-您不应该直接更改地图,有些地图会更改 不允许上述任何一种或两种方法

    具体而言,您的(1)、(2)和(3)是不允许的

    您可以通过
    Map
    对象设置现有键的值,但是
    Set.iterator()
    文档明确排除了这一点,并且它将是特定于实现的:

    如果在对集合进行迭代时修改映射(除了通过迭代器自己的删除操作,或通过迭代器返回的映射项上的setValue操作),则迭代的结果未定义。(增加重点)


    没有全球性的答案。地图界面允许用户进行选择。不幸的是,我认为jdk中的所有实现都使用fail-fast实现(这里是fail-fast的定义,如中所述):

    所有这些函数返回的迭代器 类的“集合视图方法”是 快速失败:如果映射在结构上是 修改后的任何时间 迭代器是以任何方式创建的,除了 通过迭代器自己的移除 方法,迭代器将抛出 ConcurrentModificationException。因此 面对并行 修改后,迭代器将失败 迅速而干净,而不是 冒着武断、不确定的风险 在不确定的时间内的行为 未来


    我确认你的建议很好。Map.Entry.setValue()的工作原理类似于一个符咒,Iterator.remove()也一样。为了完整性,如何通过public mutator修改迭代器当前值?映射不可能对每个条目的方法调用都有可见性,对吗?这些方法尝试快速失败,但由于内存并发性问题,如果修改是在另一个线程中完成的,它们可能并不总是这样。始终按照API文档进行编程;千万不要因为“我试过了,它成功了”而违反它,因为它可能只适用于(a)JVM,或(b)硬件,或(c)特定配置,但不适用于其他配置。