Why does it.next() throw java.util.ConcurrentModificationException?

前端 未结 3 1978
情书的邮戳
情书的邮戳 2020-12-29 13:00
final Multimap terms = getTerms(bq);
        for (Term t : terms.keySet()) {
            Collection C = new HashSet(t         


        
3条回答
  •  太阳男子
    2020-12-29 13:49

    Vineet Reynolds has explained in great details the reasons why collections throw a ConcurrentModificationException (thread-safety, concurrency). Swagatika has explained in great details the implementation details of this mechanism (how collection and iterator keep count of the number of modifications).

    Their answers were interesting, and I upvoted them. But, in your case, the problem does not come from concurrency (you have only one thread), and implementation details, while interesting, should not be considered here.

    You should only consider this part of the HashSet javadoc:

    The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

    In your code, you iterate over your HashSet using its iterator, but you use the HashSet's own remove method to remove elements ( C.remove(c) ), which causes the ConcurrentModificationException. Instead, as explained in the javadoc, you should use the Iterator's own remove() method, which removes the element being currently iterated from the underlying collection.

    Replace

                    if(c.isSomething()) C.remove(c);
    

    with

                    if(c.isSomething()) it.remove();
    

    If you want to use a more functional approach, you could create a Predicate and use Guava's Iterables.removeIf() method on the HashSet:

    Predicate ignoredBooleanClausePredicate = ...;
    Multimap terms = getTerms(bq);
    for (Term term : terms.keySet()) {
        Collection booleanClauses = Sets.newHashSet(terms.get(term));
        Iterables.removeIf(booleanClauses, ignoredBooleanClausePredicate);
    }
    

    PS: note that in both cases, this will only remove elements from the temporary HashSet. The Multimap won't be modified.

提交回复
热议问题