Reputation: 129
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
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