How to remove and add elements to TreeMap while iterating?
Asked Answered
M

6

9

I want to write code like this -

for (Map.Entry<Long, Integer> e : map.entrySet()){
    map.remove(k);
    map.put(x, value);
}

but I got java.util.ConcurrentModificationException I tried to use Iterator also but I got the same Exception

Meerschaum answered 19/5, 2013 at 16:46 Comment(3)
@ZouZou I googled for this and found this question on the first place. Google isn't enough, content is also needed :-)Uzzia
Can u pls attach the code for the iterator. The above code will certainly give u a concurrent modification Exception. You are iterating through the keyset as well as modifying the map at the same time. This is a recipe for disaster.Toothpick
Added an answer below with a sample code.Toothpick
T
11

Explanation why it caused ConcurrentModificationException

map.remove(k);
map.put(x, value);

for-each loop also internally create a iterator of the entrySet of map. While iterating over map you have modified the structure of the map by putting the value again to the map (map.put(x,value)) which cause this ConcurrentModificationException.

It is even well explained in documentation -

The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

How to solve this -

you must change the change the structure of this map while iterating, you can insert this values later, like keep a temporary map and add this to the main map once iteration is finished his job.

Map<Long, Integer> tempMap = new HashMap<>();
for (Map.Entry<Long, Integer> e : map.entrySet()){
    map.remove(k);
    tempMap.put(x, value);
}
map.putAll(tempMap);
Trainbearer answered 19/5, 2013 at 17:10 Comment(0)
R
5

Iterate over a copy and you can add/remove just fine:

for (Map.Entry<Long, Integer> e : new LinkedHashMap<Long, Integer>(map).entrySet()){
    map.remove(k);
    map.put(x, value);
}

It's not even any more lines of code, because the copy ims made in-line via the copy constructor. LinkedHashMap was chosen to preserve iteration order (if that matters).

Ridicule answered 20/5, 2013 at 4:39 Comment(0)
T
2

A sample code snippet for removing an element from the map is given below.

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

If your code involves a lot of addition and removal , you might just want to use ConcurrentHashMap.ConcurrentHashMap

Toothpick answered 15/9, 2014 at 18:12 Comment(1)
it.next() is not boolean and on top of this when the iterator has no more elements, it.next() won't be null, but instead will throw java.util.NoSuchElementException. So, use it.hasNext()Autoclave
B
1

You will have to create a copy of your map using copy constructor. Now iterate on 1 and modify second map. I am assuming that you will not need to iterate newly added value as it wont make much sense.

You can achieve your task by creating a copy is because the keys will remain same in both.

EDIT:

I dont think its a good idea to iterate the newly added element to a Hashmap. If you check the api's provided by Iterator then you will find only remove method, there is no add method in it. There is a reason behind this and you can check javadoc for this. Now coming to the point, on how to iterate newly added element.

  1. Create a copy of your HashMap. So you will iterate one and modify the the other Map.
  2. As the requirement is to both add and remove elements in Map, i would like to use ListIterator for this [this is different from normal Iterator].
  3. I will get the keyset of Map1 and convert it to a list using ArrayList(Collection<? extends E> c).
  4. Now i will get ListIterator from List created in step 3, and add, remove elements in ListIterator as well as in Map2 [Remeber you need to add , remove both in ListIterator and Map2].
Biforate answered 19/5, 2013 at 16:56 Comment(2)
no I need to iterate over this new values the new added values will be greater than the current one so I need to iterate over them tooMeerschaum
see my edit. Using newly added steps you can perform add and remove both.Biforate
T
0

Because you can't do that.

An easy solution is to use another temporary map where you put the values you want and finally switch pointers with the original one (i.e Map = newMap )

Tailstock answered 19/5, 2013 at 17:3 Comment(2)
I need to iterate over new added valuesMeerschaum
then make a while loop and keep doing this until you're done.Tailstock
G
0

Try going through the map as follows

while (tree_map.size() > 0){
     // if k is key
     if (tree_map.containsKey()){
        tree_map.remove(k);
     }
     tree_map.put(x, value);
     break;
     // can go through the for loop or other code as per requirements
 }
Geocentric answered 30/1, 2022 at 10:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.