1

Currently my code is causing intermittent ConcurrentModificationException errors, probably because of the way I am looping through the HashMap:

for (Map.Entry<String, Entity> entry : entities.entrySet()) {
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        entities.remove(key);
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);
}
// updateInfo call
ViewManager.getInstance().updateInfo(summary());
}

How does one continuously loop though a HashMap and avoid a ConcurrentModificationException error?

CoolBeans
  • 20,654
  • 10
  • 86
  • 101
Ein Doofus
  • 495
  • 1
  • 5
  • 12
  • possible duplicate of [Remove Elements from a HashSet while Iterating](http://stackoverflow.com/questions/1110404/remove-elements-from-a-hashset-while-iterating) – Rob Hruska Oct 12 '11 at 02:26

5 Answers5

5

You cannot modify a map while looping through it. You either have to make a copy of the map, use a ConcurrentHashMap, or use an iterator. If it is in a multi threaded environment, then you can do the modification in a synchronized block.

Another option is to use an iterator.

I rewrote your for for loop with an iterator below:

for(Iterator<Map.Entry<String, Entity>> iterator = entities.entrySet().iterator(); iterator.hasNext(); ){
    Map.Entry<String, Entity> entry = iterator.next();
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        //Notice using an iterator to remove 
        iterator.remove();
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);

}

I am not sure about the part of continuously looping a HashMap. A hash map has a finite set of keys, so you loop through the key set generally. If you for some reason want to loop continuously then you need to first tell us the reason behind it and also the terminal condition of that continuous loop (it cant really be forever, can it?).

CoolBeans
  • 20,654
  • 10
  • 86
  • 101
3

As documented in the other answers, using a Iterator based for-loop, instead of a for-each loop, is your best bet for avoiding ConcurrentModificationExemptions. As for the infinite looping, have a look at the cycle method in Guava's Iterators static utility class. It takes an Iterable (such as a HashMap) and returns an Iterator that continuously loops over the data until either the Iterable is empty or you break the loop.

jcwayne
  • 741
  • 4
  • 5
1

how about using an iterator and while loop?

Iterator<String> iterator = map.iterator();
String key;
String value;
while (iterator.hasNext()) {
 key = iterator.next();
 value = map.get(key);
}
Denaeught
  • 11
  • 3
1

You cannot call remote(key) method while looping, but you can remove entries via an iterator:

Map<String, String> map = new HashMap<String, String>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();)
{
    Map.Entry<String, String> curEntry = i.next();
    if (curEntry.getKey().equals("two"))
        i.remove();
}
prunge
  • 22,460
  • 3
  • 73
  • 80
0

Assuming that you are accessing the map in only on thread, use an iterator, as the other guys suggest.

I was thinking about the performance when iterating over a hashmap, so i did a quick test of 25 iterations over 10^6 random Longs and removing 10% of then, using different map implementations: ConcurrentHashMap, HashMap, LinkedHashMap and a TreeMap.

The linked hashmap is supposedly tailored for iterating, and it seems to be the most efficient. I suppose the spikes are due to gc.

...but the differences are smaller than I had anticipated.

enter image description here

KarlP
  • 5,149
  • 2
  • 28
  • 41