user26372
user26372

Reputation: 129

Java Guava: Remove and put back elements from Multimap while iterating

What I'm trying to achieve is the following: While iterating over both the keys and values of a Multimap<K,V>, I want to remove and put back elements from this list. Any approach I've tried ends up in a ConcurrentModificationException. This remove-and-put-back-approach is required to implement a backtrack search (see here: Implementing a backtrack search with heuristic? )

This may look like:

Multimap<K,V> multimap = HashMultimap.create();
Iterator keyIterator = multimap.keySet().iterator();

while(keyIterator.hasNext()) {
  K key = keyIterator.next();
  Collection values = multimap.get(key);

  Iterator valueIterator = values.iterator();
  while(valueIterator.hasNext()) {
    V myValue = valueIterator.next();
    if(special) {
      valueIterator.remove();
      keyIterator.remove();
      // recursion
      // put back Collection with key but without myValue <-- HOW?
    }
  }
}

Upvotes: 1

Views: 2180

Answers (1)

Zim-Zam O&#39;Pootertoot
Zim-Zam O&#39;Pootertoot

Reputation: 18148

One solution is to iterate over a copy of keySet, e.g.

K[] array = multiMap.keySet().toArray(new K[0]);
for(int i = 0; i < array.length; i++) {
    K key = array[i];
    ...
}

Changes to the underlying map won't be reflected in array, so you won't get a ConcurrentModificationException if you use an Iterator on it, and you won't get any weird behavior if you iterate over it with a for loop.

Another option is to copy-paste the source code for MultiMap into a new collection MyMultiMap, except that you'd replace the top-level HashMap with a ConcurrentHashMap - the latter's iterators won't throw ConcurrentModificationExceptions.

Another option is to coalesce the two loops into one loop, and iterate directly over the map's entries - this way you'll only have one iterator, so you won't have the problem of one iterator causing ConcurrentModificationExceptions in a second iterator.

Upvotes: 3

Related Questions