2

I am trying to replace whole key/value pair from my LinkedHashMap but seems it is not working. I am getting concurrentmodificationexception. Is there a way to replace whole key/value pair for a key at the same position without any major changes.

I tried to do the following:

    Map<String, String> testMap = new LinkedHashMap<String, String>();
    testMap.put("1", "One");
    testMap.put("2", "Two");
    testMap.put("3", "Three");
    testMap.put("4", "Four");
    testMap.put("5", "Five");
    testMap.put("6", "Six");
    /*
     * Removing an element from the Map.
     */
    Iterator<Entry<String, String>> iter = testMap.entrySet().iterator();
    while (iter.hasNext()) {
        Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next();
        System.out.print(entry.getKey() + "->" + entry.getValue() + "; ");
        if (entry.getKey().equals("1"))
            iter.remove(); // remove one entry (key/value) with key "1". Ok

        if (entry.getValue().equalsIgnoreCase("Two"))
            iter.remove(); // removing all entries (key/value) for value "Two". Ok

        if (entry.getKey().equals("3"))
            entry.setValue("Updated_Three"); // Updating value for key 3. Ok

        // Below how to now add a new key/value pair in my testMap at this position
        // without affecting any other order?
        if (entry.getKey().equals("4")) {
            iter.remove();
            // How to now add a new key/value pair at this position without affecting any
            // other order.
            // testMap.put("44", "FourFour"); // Removing entry with key 4 and adding a new
            // key/valuepair to hashmap. It throws ConcurrentModificationException. Any
            // other way to perform this?
        }
    }
ric
  • 627
  • 1
  • 12
  • 23
vinsinraw
  • 2,003
  • 1
  • 16
  • 18
  • 2
    Why? The iteration order of a `LinkedHashMap` is *defined* as insertion order. Why do you want to break it? – user207421 Dec 22 '17 at 06:44
  • @EJP My usecase is to add an entry (key/value) at the same position where the old key/value pair entry is removed. If you have any idea, please share... – vinsinraw Dec 22 '17 at 06:54
  • @vinS You will get CME if u uncomment testMap.put("44", "FourFour"); Actually I wanted to know if there is any alternative way to this statement for replacing key/value at the same position. – vinsinraw Dec 22 '17 at 07:21
  • @vinS No it is not. My query is "How to replace whole key/value pair from a LinkedHashmap at the same replaced position" I have not focused on CME explicitly. I am curious to know if removal and addition of new entry (kay/value) pair can happen in sequence while traversing through map entries.. – vinsinraw Dec 22 '17 at 07:53
  • 2
    Ok. It is very clear now. You do not want to use other data structures (as suggested in answers). You should mention it in the question to avoid un-necessary answers. – vinS Dec 22 '17 at 07:55

2 Answers2

3

As far as I have understood, you want to stick with LinkedHashMap. If you will try to add new data (change the structure of the LinkedHashMap) while iterating over this, you will get ConcurrentModificationException.

Below code might fulfill your requirement :

public static void main(String args[]) throws IOException {

    Map<String, String> testMap = new LinkedHashMap<>();
    testMap.put("1", "One");
    testMap.put("2", "Two");
    testMap.put("3", "Three");
    testMap.put("4", "Four");

    int indexOfFourtyFour = -1;
    System.out.println("Test Map before :: " + testMap);

    Iterator<Entry<String, String>> itr = testMap.entrySet().iterator();
    int index = 0;
    while (itr.hasNext()) {
        Map.Entry<String, String> entry = (Map.Entry<String, String>) itr.next();
        if (entry.getKey().equals("3")) {
            itr.remove();
            indexOfFourtyFour = index;
        }
        index ++;
    }
    if (indexOfFourtyFour > -1) {
        add(testMap, indexOfFourtyFour, "44", "FourFour");
    }
    System.out.println("Test Map after :: " + testMap);
}

public static <K, V> void add(Map<K, V> map, int index, K key, V value) {
    assert (map != null);
    assert !map.containsKey(key);
    assert (index >= 0) && (index < map.size());

    int i = 0;
    List<Entry<K, V>> rest = new ArrayList<Entry<K, V>>();
    for (Entry<K, V> entry : map.entrySet()) {
        if (i++ >= index) {
            rest.add(entry);
        }
    }
    map.put(key, value);
    for (int j = 0; j < rest.size(); j++) {
        Entry<K, V> entry = rest.get(j);
        map.remove(entry.getKey());
        map.put(entry.getKey(), entry.getValue());
    }
}

Output :

Test Map before :: {1=One, 2=Two, 3=Three, 4=Four}
Test Map after :: {1=One, 2=Two, 44=FourFour, 4=Four}

Code for add element at specific index in LinkedHashMap from HERE

vinS
  • 1,417
  • 5
  • 24
  • 37
  • 1
    Thank you @vinS. It worked :). though I had thought Java API could had some easy solution using iterator or entry object's methods similar to iter.remove() or entry.setValue(..). Any thoughts how this can be achieved using java8? – vinsinraw Dec 22 '17 at 16:14
0

In case you are using a LinkedHashMap and want to work with the KEY instead of an index you could do the following (based on the answer of @vinS):

/**
   * Replaces the {@param originKey} and it's value with the new {@param key} and {@param value} for
   * the {@param map}. <b>CAUTION: This only works on {@link LinkedHashMap}!</b>
   *
   * @param map a {@link LinkedHashMap} to replace the key and value on
   * @param originKey the KEY which will be replaced
   * @param key the new KEY used
   * @param value the new VALUE used
   * @param <K> type of the KEYs for the {@link Map}
   * @param <V> type of the VALUEs for the {@link Map}
   */
  private static <K, V> void replaceAtPosition(Map<K, V> map, K originKey, K key, V value) {
    assert (map != null);
    assert !map.containsKey(key);
    Map<K, V> newMap = new LinkedHashMap<>(map.size());
    for (Map.Entry<K, V> entry : map.entrySet()) {
      if (entry.getKey().equals(originKey)) {
        newMap.put(key,value);
      }else{
        newMap.put(entry.getKey(),entry.getValue());
      }
    }
    map.clear();
    map.putAll(newMap);
  }
Pwnstar
  • 2,333
  • 2
  • 29
  • 52