[
https://issues.apache.org/jira/browse/COLLECTIONS-663?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16967846#comment-16967846
]
Christophe Schmaltz commented on COLLECTIONS-663:
-------------------------------------------------
Hi [~Guoping1] ,
thank you for looking into this. I worked around my problem since then.
Maybe you want to add in the documentation of {{MultiValuedMap.mapIterator()}}
(or better in it's implementation {{AbstractMultiValuedMap.mapIterator()}})
that it doesn't support {{setValue(Object)}}, as it's documented for asMap().
But I think the initial issue needs documentation even more:
{code:java}
@Test
public void test() {
MultiValuedMap<Integer, Integer> multiMap = new
HashSetValuedHashMap<>();
multiMap.put(1, 10);
multiMap.put(2, 20);
for (Collection<Integer> innerCollection :
multiMap.asMap().values()) {
for (Iterator<Integer> iterator =
innerCollection.iterator(); iterator.hasNext();) {
Integer i = iterator.next();
iterator.remove(); // only the innerCollection
is altered
}
// innerCollection.add(6); // adding stuff back should
also work...
}
}{code}
This test unexpectedly throws a ConcurrentModificationException, which is a lot
harder to understand than the UnsupportedOperationException of the other test.
The {{ConcurrentModificationException}} needs debugging to understand that it
isn't the user who removed concurrently, but the apache-commons library itself.
That {{AbstractMultiValuedMap.ValuesIterator.remove()}} is calling
{{AbstractMultiValuedMap.this.remove(key);}} is incorrect if the user was using
an iterator over the multimap:
{code:java}
// AbstractMultiValuedMap.ValuesIterator.remove():
@Override
public void remove() {
iterator.remove();
if (values.isEmpty()) {
// this is buggy if the user was iterating over the
AbstractMultiValuedMap
AbstractMultiValuedMap.this.remove(key);
}
}
{code}
Maybe MultiValuedMap.asMap() needs some documentation that it doesn't support
{{remove()}} in case of nested usage of {{iterator()}}.
Or find a way to call enclosingIterator.remove():
{code:java}
// AbstractMultiValuedMap.ValuesIterator.remove():
@Override
public void remove() {
iterator.remove();
if (values.isEmpty()) {
if (hasEnclosingIterator()) {
enclosingIterator.remove(); // nested iteration
} else {
AbstractMultiValuedMap.this.remove(key); // non nested usage
}
}
}
{code}
hasEnclosingIterator() and enclosingIterator have to be implemented, somehow :D
> Unexpected ConcurrentModificationException when altering Collection of a
> MultiValuedMap
> ---------------------------------------------------------------------------------------
>
> Key: COLLECTIONS-663
> URL: https://issues.apache.org/jira/browse/COLLECTIONS-663
> Project: Commons Collections
> Issue Type: Bug
> Reporter: Christophe Schmaltz
> Assignee: Bruno P. Kinoshita
> Priority: Trivial
>
> Testcase:
> {code} @Test
> public void test() {
> MultiValuedMap<Integer, Integer> multiMap = new
> HashSetValuedHashMap<>();
> multiMap.put(1, 10);
> multiMap.put(2, 20);
> for (Collection<Integer> innerCollection :
> multiMap.asMap().values()) {
> for (Iterator<Integer> iterator =
> innerCollection.iterator(); iterator.hasNext();) {
> Integer i = iterator.next();
> iterator.remove(); // only the innerCollection
> is altered
> }
> // innerCollection.add(6); // adding stuff back should
> also work...
> }
> }{code}
> This test unexpectedly throws a ConcurrentModificationException.
> The issue is that when calling {{iterator.remove()}} the
> {{AbstractMultiValuedMap.ValuesIterator}} detects that the Collection is
> empty and calls {{AbstractMultiValuedMap.this.remove(key);}}.
> It may be better if the iterator of the inner collection had a reference on
> the iterator if the outer map and called {{containerIterator.remove()}}
> instead.
> *Note:* this solution would again present issues if the user tries to add new
> elements in this now empty collection (which was removed from the parent).
> In the current state, it is quite unclear why an exception is thrown, without
> debugging the code.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)