Java 如何在迭代时删除元素并将其添加到树映射中?

Java 如何在迭代时删除元素并将其添加到树映射中?,java,treemap,Java,Treemap,我想写这样的代码- for (Map.Entry<Long, Integer> e : map.entrySet()){ map.remove(k); map.put(x, value); } for(Map.Entry e:Map.entrySet()){ 地图。删除(k); map.put(x,值); } 但是我得到了java.util.ConcurrentModificationException 我也尝试使用了迭代器,但我得到了相同的异常您必须使用复制构造

我想写这样的代码-

for (Map.Entry<Long, Integer> e : map.entrySet()){
    map.remove(k);
    map.put(x, value);
}
for(Map.Entry e:Map.entrySet()){
地图。删除(k);
map.put(x,值);
}
但是我得到了
java.util.ConcurrentModificationException

我也尝试使用了
迭代器
,但我得到了相同的
异常

您必须使用复制构造函数创建映射的副本。现在在1上迭代并修改第二个映射。 我假设您不需要迭代新增加的值,因为这没有多大意义

您可以通过创建副本来完成任务,因为这两个副本中的键保持不变

编辑:

我认为将新添加的元素迭代到Hashmap不是一个好主意。如果您检查迭代器提供的api,那么您将发现只有remove方法,而没有add方法。这背后有一个原因,您可以检查javadoc。 现在开始讨论如何迭代新添加的元素

  • 创建
    HashMap
    的副本。因此,您将迭代其中一个并修改另一个
    Map
  • 由于需要在
    Map
    中添加和删除元素,因此我想使用
    ListIterator
    来实现这一点[这与普通的
    迭代器不同]

  • 我将获取Map1的
    键集
    ,并使用
    ArrayList(Collection将其转换为列表,因为您不能这样做

    一个简单的解决方案是使用另一个临时映射,在其中放置所需的值,并最终将指针切换到原始映射(即map=newMap)

    解释为什么它会导致
    ConcurrentModificationException

    对于每个循环,还可以在内部为
    map
    entrySet
    创建一个迭代器。在对map进行迭代时,您通过将值再次放入map(
    map.put(x,value)
    )来修改map的结构,这会导致此
    ConcurrentModificationException

    这一点在本书中得到了很好的解释-

    该类的所有“集合”视图返回的迭代器 方法“是快速失效的:如果地图在任何时候被结构修改 创建迭代器后的时间,以任何方式,除了通过 迭代器自己的remove方法,迭代器将抛出 ConcurrentModificationException。因此 修改后,迭代器会快速、干净地失败,而不是 在不确定的时间冒任意、不确定行为的风险 将来

    如何解决这个问题-

    您必须在迭代时更改此映射的结构,您可以稍后插入此值,例如保留一个临时映射,并在迭代完成后将其添加到主映射

    Map<Long, Integer> tempMap = new HashMap<>();
    for (Map.Entry<Long, Integer> e : map.entrySet()){
        map.remove(k);
        tempMap.put(x, value);
    }
    map.putAll(tempMap);
    
    Map tempMap=newhashmap();
    对于(Map.Entry e:Map.entrySet()){
    地图。删除(k);
    tempMap.put(x,值);
    }
    map.putAll(tempMap);
    
    在副本上迭代,您可以添加/删除:

    for (Map.Entry<Long, Integer> e : new LinkedHashMap<Long, Integer>(map).entrySet()){
        map.remove(k);
        map.put(x, value);
    }
    
    for(Map.Entry e:newlinkedhashmap(Map.entrySet()){
    地图。删除(k);
    map.put(x,值);
    }
    

    它甚至没有更多的代码行,因为复制ims是通过复制构造函数在线生成的。
    LinkedHashMap
    被选择来保留迭代顺序(如果这很重要)。

    下面给出了从映射中删除元素的示例代码段

    for(Iterator<Map.Entry<Long, Integer>> it = map.entrySet().iterator();it.next();)
    {
      Map.Entry<String, String> entry = it.next();
     if(//some logic)    
     it.remove();
    }
    
    for(Iterator it=map.entrySet().Iterator();it.next();)
    {
    Map.Entry=it.next();
    if(//某些逻辑)
    it.remove();
    }
    

    如果您的代码涉及大量的添加和删除,您可能只想使用ConcurrentHashMap。

    否我需要迭代这些新值新添加的值将大于当前值,因此我需要迭代它们以查看我的编辑。使用新添加的步骤,您可以同时执行添加和删除。我需要迭代新添加的值Luesen做一个while循环,并一直这样做,直到你完成为止。@ZouZou我搜索了这个问题,首先发现了这个问题。Google是不够的,还需要内容:-)你能附上迭代器的代码吗。上面的代码肯定会给你一个并发修改异常。您在遍历键集的同时也在修改映射。这是造成灾难的原因。在下面添加了一个带有示例代码的答案。
    it.next()
    不是布尔值,而且当迭代器没有更多元素时,不会为null,而是抛出
    java.util.NoSuchElementException
    。因此,使用
    it.hasNext()
    for(Iterator<Map.Entry<Long, Integer>> it = map.entrySet().iterator();it.next();)
    {
      Map.Entry<String, String> entry = it.next();
     if(//some logic)    
     it.remove();
    }