【问题标题】:Changing HashMap keys during iteration在迭代期间更改 HashMap 键
【发布时间】:2011-05-13 06:07:35
【问题描述】:

是否可以在迭代期间更改同一 HashMap 实例的键?因为地图条目集没有方法entry.setKey()。现在我能想到的是创建另一个 HashMap...

MultipartParsingResult parsingResult = parseRequest(request);

Map<String, String[]> mpParams = parsingResult.getMultipartParameters();
Map<String, String[]> mpParams2 = new HashMap<String, String[]>();

Iterator<Entry<String,String[]>> it = mpParams.entrySet().iterator();

while (it.hasNext()) {
    Entry<String,String[]> entry = it.next();
    String name = entry.getKey();

    if (name.startsWith(portletNamespace)) {
        mpParams2.put(name.substring(portletNamespace.length(), name.length()), entry.getValue());
    }
    else {
        mpParams2.put(name, entry.getValue());
    }
}

【问题讨论】:

    标签: java set hashmap iteration


    【解决方案1】:

    您应该将信息保留在其他集合中,以便在迭代后对其进行修改。您只能在迭代器期间使用 iterator.remove() 删除条目。 HashMap 合约禁止在迭代期间对其进行变异。

    【讨论】:

    • 您不能永远更改 Map 中的键值。
    • 所以从性能的角度来看,我这里的解决方案好吗?因为每小时会有数千个这样的电话
    • @EJP 我在这里更改的只是地图的键
    • 这就是我的观点。您不能更改 Map 中键对象的值。请参阅地图的 Javadoc。
    【解决方案2】:

    您可能希望对 HashMap 中的键或值进行四种常见的修改。

    1. 要更改 HashMap 键,请使用 get 查找值对象,然后删除旧键并将其与新键放在一起。
    2. 要更改值对象中的字段,请使用 get 键查找值对象,然后使用其 setter 方法。
    3. 要完全替换值对象,只需在旧键处放置一个新值对象即可。
    4. 要将值对象替换为基于旧的值对象,请使用 get 查找值对象,创建一个新对象,从旧对象复制数据,然后将新对象放在同一键下。

    类似这个例子。

    static class Food
        {
        // ------------------------------ FIELDS ------------------------------
    
        String colour;
    
        String name;
    
        float caloriesPerGram;
        // -------------------------- PUBLIC INSTANCE  METHODS --------------------------
    
        public float getCaloriesPerGram()
            {
            return caloriesPerGram;
            }
    
        public void setCaloriesPerGram( final float caloriesPerGram )
            {
            this.caloriesPerGram = caloriesPerGram;
            }
    
        public String getColour()
            {
            return colour;
            }
    
        public void setColour( final String colour )
            {
            this.colour = colour;
            }
    
        public String getName()
            {
            return name;
            }
    
        public void setName( final String name )
            {
            this.name = name;
            }
    
        public String toString()
            {
            return name + " : " + colour + " : " + caloriesPerGram;
            }
    
        // --------------------------- CONSTRUCTORS ---------------------------
    
        Food( final String name, final String colour, final float caloriesPerGram )
            {
            this.name = name;
            this.colour = colour;
            this.caloriesPerGram = caloriesPerGram;
            }
        }
    
    // --------------------------- main() method ---------------------------
    
    /**
     * Sample code to TEST HashMap Modifying
     *
     * @param args not used
     */
    public static void main( String[] args )
        {
        // create a new HashMap
        HashMap<String, Food> h = new HashMap<String, Food>( 149
                /* capacity */,
                0.75f
                /* loadfactor */ );
    
        // add some Food objecs to the HashMap
        // see http://www.calorie-charts.net  for calories/gram
        h.put( "sugar", new Food( "sugar", "white", 4.5f ) );
        h.put( "alchol", new Food( "alcohol", "clear", 7.0f ) );
        h.put( "cheddar", new Food( "cheddar", "orange", 4.03f ) );
        h.put( "peas", new Food( "peas", "green", .81f ) );
        h.put( "salmon", new Food( "salmon", "pink", 2.16f ) );
    
        // (1) modify the alcohol key to fix the spelling error in the key.
        Food alc = h.get( "alchol" );
        h.put( "alcohol", alc );
        h.remove( "alchol" );
    
        // (2) modify the value object for sugar key.
        Food sug = h.get( "sugar" );
        sug.setColour( "brown" );
        // do not need to put.
    
        // (3) replace the value object for the cheddar key
        // don't need to get the old value first.
        h.put( "cheddar", new Food( "cheddar", "white", 4.02f ) );
    
        // (4) replace the value object for the peas key with object based on previous
        Food peas = h.get( "peas" );
        h.put( "peas", new Food( peas.getName(), peas.getColour(), peas.getCaloriesPerGram() * 1.05f ) );
    
        // enumerate all the keys in the HashMap in random order
        for ( String key : h.keySet() )
            {
            out.println( key + " = " + h.get( key ).toString() );
            }
        }// end main
    }
    

    希望对你有帮助

    【讨论】:

      【解决方案3】:

      也许这会有所帮助:

      map.put(newkey,map.remove(oldkey));
      

      【讨论】:

      • 如果我正在迭代键集,这个新添加的键是否会显示在现有键集中?
      【解决方案4】:

      最好的办法是将地图复制到新的地图中,并进行您想要的修改,然后返回新地图并销毁旧地图。 不过,我想知道这个解决方案对性能有何影响。

      【讨论】:

        【解决方案5】:

        当我需要更改地图条目的键时,我进入了这个线程。 在我的情况下,我在 Map 中有一个 JSON 表示,这意味着它可以保存地图或地图列表,这是代码:

        private Map<String,Object> changeKeyMap(Map<String, Object> jsonAsMap) throws InterruptedException {
        
            Map<String,Object> mapClone = new LinkedHashMap<>();
            for (Map.Entry<String, Object> entry : jsonAsMap.entrySet()) {
                if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
                Object value = entry.getValue();
                if (entry.getValue() instanceof Map) {
                    value = changeKeyMap((Map) entry.getValue());
                } else if (isListOfMaps(entry.getValue())) {
                    value = changeKeyListOfMaps((List<Map<String, Object>>) entry.getValue());
                }
                String changedKey = changeSingleKey(entry.getKey());
                mapClone.put(changedKey, value);
            }
            return mapClone;
        }
        
        private List<Map<String,Object>> changeKeyListOfMaps(List<Map<String,Object>> listOfMaps) throws InterruptedException {
            List<Map<String,Object>> newInnerMapList = new ArrayList<>();
            for(Object singleMapFromArray :listOfMaps){
                Map<String,Object> changeKeyedMap = changeKeyMap((Map<String, Object>) singleMapFromArray);
                newInnerMapList.add(changeKeyedMap);
            }
            return newInnerMapList;
        }
        private boolean isListOfMaps(Object object) {
            return object instanceof List && !((List) object).isEmpty() && ((List) object).get(0) instanceof Map;
        }
        
        private String changeSingleKey(String originalKey) {
            return originalKey + "SomeChange"
        }
        

        【讨论】:

        • 我的语言中有句谚语说“我买了糖浆,结果却是蜂蜜”。我发现它与您的答案非常相关。谢谢 Robocide!
        猜你喜欢
        • 1970-01-01
        • 2014-10-02
        • 2020-06-20
        • 2021-07-26
        • 2022-10-25
        • 2011-03-21
        • 2010-12-02
        • 2018-09-16
        相关资源
        最近更新 更多