【问题标题】:How can I iterate over an object while modifying it in Java? [duplicate]在 Java 中修改对象时如何迭代对象? [复制]
【发布时间】:2011-03-31 20:48:24
【问题描述】:

可能的重复:
Java: Efficient Equivalent to Removing while Iterating a Collection
Removing items from a collection in java while iterating over it

我正在尝试遍历HashMap

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

... 并提取group0 中的每个元素。这是我的方法:

// iterate through all Members in group 0 that have not been assigned yet
for (Map.Entry<String, Integer> entry : group0.entrySet()) {

    // determine where to assign 'entry'
    iEntryGroup = hasBeenAccusedByGroup(entry.getKey());
    if (iEntryGroup == 1) {
        assign(entry.getKey(), entry.getValue(), 2);
    } else {
        assign(entry.getKey(), entry.getValue(), 1);
    }
}

这里的问题是每次调用assign()都会从group0中移除元素,从而修改它的大小,从而导致如下错误:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
    at java.util.HashMap$EntryIterator.next(HashMap.java:834)
    at java.util.HashMap$EntryIterator.next(HashMap.java:832)
    at liarliar$Bipartite.bipartition(liarliar.java:463)
    at liarliar$Bipartite.readFile(liarliar.java:216)
    at liarliar.main(liarliar.java:483)

那么...我如何在 group0 动态变化时循环遍历元素?

【问题讨论】:

标签: java exception hashmap concurrentmodification


【解决方案1】:

其他人已经提到了正确的解决方案而没有真正拼写出来。所以这里是:

Iterator<Map.Entry<String, Integer>> iterator = 
    group0.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, Integer> entry = iterator.next();

    // determine where to assign 'entry'
    iEntryGroup = hasBeenAccusedByGroup(entry.getKey());

    if (iEntryGroup == 1) {
        assign(entry.getKey(), entry.getValue(), 2);
    } else {
        assign(entry.getKey(), entry.getValue(), 1);
    }

    // I don't know under which conditions you want to remove the entry
    // but here's how you do it
    iterator.remove();
}

另外,如果你想在你的assign函数中安全地改变map,你需要传入迭代器(其中你只能使用remove函数并且只能使用一次)或者entry来改变值。

【讨论】:

  • 谢谢...这正是我要找的!
【解决方案2】:

在您的特定情况下,我不会修改 HashMap 的结构,而只是将您要删除的值设为空。然后,如果您最终访问一个空值,请跳过它。

在一般情况下,我更喜欢将 Stack 用于此类事情,因为它们特别容易可视化,因此我倾向于较少遇到边界条件问题(只是保持弹出“直到为空)。

【讨论】:

  • 啊...好主意 :) 但是在这里使用堆栈是完全不正确的...例如,如果我想检查一个元素是否存在,那么这里的效率会非常低下。对于我的目标,效率和速度是必须的。但我喜欢 null-ing 的想法。 +1
【解决方案3】:

【讨论】:

  • .. 有趣。谢谢你的建议。您能否简要谈谈使用 ConcurrentHashMap 的性能优势?在检查元素是否存在、获取元素、删除元素、插入元素等方面,使用这种数据结构是否有显着改进?
【解决方案4】:

正如我在这里的回答所说:

Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

使用 Iterator.remove()

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
【解决方案5】:

在这种情况下,assign如何修改group0?需要更多细节。通常,您无法在迭代集合时对其进行修改。你通过Iterator接口修改。

【讨论】:

    【解决方案6】:

    如果要在循环遍历集合时修改集合,则需要使用实际的迭代器及其 remove 方法。使用 foreach 构造实际上没有任何方法可以做到这一点。

    如果您尝试在一次迭代中删除多个条目,则需要循环遍历不受地图支持的内容。

    Set<String> keys = new HashSet<String>(group0.keySet());
    for (String key : keys) {
      if (group0.containsKey(key)) {
        Integer value = group0.get(key);
        //your stuff 
      }
    }
    

    【讨论】:

    • assign() 也可能从 group0 中删除多个元素...因此有可能一次迭代将删除 group0 中的所有元素,而无需第二次迭代。你能发布迭代器如何工作的代码吗?
    猜你喜欢
    • 2020-05-04
    • 1970-01-01
    • 2013-03-07
    • 2015-08-26
    • 2020-05-24
    • 2012-12-09
    • 1970-01-01
    • 2015-11-07
    • 2021-11-29
    相关资源
    最近更新 更多