【问题标题】:How to remove multiple mappings in hashmap without ConcurrentModificationException?如何在没有 ConcurrentModificationException 的情况下删除 hashmap 中的多个映射?
【发布时间】:2015-07-30 21:30:38
【问题描述】:

我有 2 个哈希图:HashMap<String, Word> hmSmall, hmBig。每个中的映射都是多对一。因此,基于某些标准,我必须删除与两个哈希图中的特定值相对应的所有映射。为此,我正在关注this 的回答。

问题是我在遍历哈希图时仍然得到ConcurrentModificationException

代码如下:

for (Iterator<Word> it = hmSmall.values().iterator(); it.hasNext(); i++) {
            Word value = it.next();//java.util.ConcurrentModificationException here
            String key = value.getKey();
            if (hmBig.containsKey(key)) {
                // if big contains less then remove from big
                // else it.remove

                if (hmBig.get(key).getTotalOccurances() < value
                        .getTotalOccurances()) {

                    hmBig.values().removeAll(
                            Collections.singleton(hmBig.get(key)));

                } else {

                    // it.remove(); not using this based on https://stackoverflow.com/a/30214164/848377
                    hmSmall.values().removeAll(Collections.singleton(value));

                }

            }
        }

有简单的出路吗?

【问题讨论】:

    标签: java


    【解决方案1】:

    所以这里的关键是不要在迭代的时候改变hashmap的大小。因此,我没有删除循环中的条目,而是在数组列表中添加了键。当循环结束时,我遍历了那个arraylist并删除了与arraylist中的键对应的hashmap的条目。

    代码如下:

    ArrayList<String> alsmallhm=new ArrayList<String>();
            for (Iterator<Word> it = hmSmall.values().iterator(); it.hasNext(); i++) {
                Word value = it.next();//java.util.ConcurrentModificationException here
                String key = value.getKey();
                if (hmBig.containsKey(key)) {
                    // if big contains less then remove from big
                    // else it.remove
    
                    if (hmBig.get(key).getTotalOccurances() < value
                            .getTotalOccurances()) {
    
                        hmBig.values().removeAll(
                                Collections.singleton(hmBig.get(key)));
    
                    } else {
    
                        // it.remove();
                        alsmallhm.add(key);
                        /*hmSmall.values().removeAll(Collections.singleton(value));*/
    
                    }
    
                }
            }
    
            for(String s:alsmallhm){
                hmSmall.values().removeAll(Collections.singleton(hmSmall.get(s)));
            }
    

    【讨论】:

      【解决方案2】:

      正如@Ejp 建议的那样,Iterator#remove() 是摆脱ConcurrentModificationException 的最佳解决方案。

      类似的帖子Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

      同样使用 java8 ,你可以很好地使用removeIf() 方法。看看Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

      【讨论】:

        【解决方案3】:

        只需将 removeAll 调用放在循环之外:

           public static void main(String[] args) {
            // The test map
            final Map<String, String> map = new HashMap<String, String>();
            map.put("Key1", "Value");
            map.put("Key2", "Value");
            map.put("Key3", "Value");
        
            .
        
        
            // Print the map to confirm it worked.
            for(final String key : map.keySet()) {
                map.values().removeAll(Collections.singleton("Value"));
               System.out.println(key + " = " + map.get(key));
            }
        }
        

        前面会导致异常(ConcurrentModificationException)试试这个:

         public static void main(String[] args) {
            // The test map
            final Map<String, String> map = new HashMap<String, String>();
            map.put("Key1", "Value");
            map.put("Key2", "Value");
            map.put("Key3", "Value");
        
        
            map.values().removeAll(Collections.singleton("Value"));
        
        
            for(final String key : map.keySet()) {
               System.out.println(key + " = " + map.get(key));
            }
        }
        

        现在可以正常使用了

        【讨论】:

          【解决方案4】:

          您的问题是,当您使用迭代器类遍历 HashMap 时,您正在通过删除元素来更改 HashMap 的大小...

          您可以将要删除的对象存储在一个单独的集合中,然后在循环后全部删除。

          对比this stackoverflow post的例子:

          Map<String, String> map = new HashMap<>();
          map.put("a", "");
          map.put("b", "");
          map.put("c", "");
          
          Set<String> set = new HashSet<> ();
          set.add("a");
          set.add("b");
          
          map.keySet().removeAll(set);
          
          System.out.println(map); //only contains "c"
          

          【讨论】:

            【解决方案5】:

            您必须在迭代时通过Iterator.remove() 删除以避免ConcurrentModificationException

            【讨论】:

            • 我必须删除所有映射。使用Iterator.remove()会删除当前值对应的所有映射吗?
            猜你喜欢
            • 2012-01-10
            • 2014-06-06
            • 1970-01-01
            • 2016-05-22
            • 1970-01-01
            • 1970-01-01
            • 2023-03-08
            • 1970-01-01
            • 2011-06-29
            相关资源
            最近更新 更多