[Q#4078518][A#4078601] How to avoid ConcurrentModificationException when iterating over a map and changing values?
https://stackoverflow.com/q/4078518
I've got a map containing some keys (Strings) and values (POJOs) I want to iterate through this map and alter some of the data in the POJO. The current code I've inherited removes the given entry, and adds it back in after making some changes to the POJO. This doesn't work well, since you shouldn't be modifying a map whilst your iterating through it (method is synchronised, but ConcurrentModificationException still appears) My question is, if I need to iterate over a map and change values, what are the best practices/methods I can use for doing so? To create a separate map and build that up as I go, then return the copy?
Answer
https://stackoverflow.com/a/4078601
Two options: The current code I've inherited removes the given entry, and adds it back in after making some changes to the POJO. Are you changing the reference to the POJO? E.g., so the entry points to something else entirely? Because if not, there's no need to remove it from the map at all, you can just change it. If you do need to actually change the reference to the POJO (e.g., the value of the entry), you can still do that in place by iterating over the Map.Entry instances from entrySet(). You can use setValue on the entry, which doesn't modify what you're iterating over. Example: The output (in no particular order) is: Visiting two Modifying it Visiting one Visiting three two=DUE one=uno three=tre …without any modification exception. You will probably want to synchronize this in case something else is also looking at / mucking with that entry.
APIzation
Map<String,String> map;
Map.Entry<String,String> entry;
Iterator<Map.Entry<String,String>> it;
// Create the map
map = new HashMap<String,String>();
map.put("one", "uno");
map.put("two", "due");
map.put("three", "tre");
// Iterate through the entries, changing one of them
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
System.out.println("Visiting " + entry.getKey());
if (entry.getKey().equals("two"))
{
System.out.println("Modifying it");
entry.setValue("DUE");
}
}
// Show the result
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
System.out.println(entry.getKey() + "=" + entry.getValue());
}
package com.stackoverflow.api;
import java.util.Iterator;
import java.util.Map;
public class Human4078601 {
public static Map<String, String> mapModify(
Map<String, String> map,
String key,
String value
) {
Map.Entry<String, String> entry;
Iterator<Map.Entry<String, String>> it;
// Iterate through the entries, changing one of them
it = map.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
System.out.println("Visiting " + entry.getKey());
if (entry.getKey().equals(key)) {
System.out.println("Modifying it");
entry.setValue(value);
}
}
return map;
}
}
package com.stackoverflow.api;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* How to avoid ConcurrentModificationException when iterating over a map and changing values?
*
* @author APIzator
* @see <a href="https://stackoverflow.com/a/4078601">https://stackoverflow.com/a/4078601</a>
*/
public class APIzator4078601 {
public static void avoidConcurrentmodificationexception()
throws Exception {
Map<String, String> map;
Map.Entry<String, String> entry;
Iterator<Map.Entry<String, String>> it;
// Create the map
map = new HashMap<String, String>();
map.put("one", "uno");
map.put("two", "due");
map.put("three", "tre");
// Iterate through the entries, changing one of them
it = map.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
System.out.println("Visiting " + entry.getKey());
if (entry.getKey().equals("two")) {
System.out.println("Modifying it");
entry.setValue("DUE");
}
}
// Show the result
it = map.entrySet().iterator();
while (it.hasNext()) {
entry = it.next();
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}