有没有办法选择“未指定的行为”而不是ConcurrentModificationException?

时间:2017-02-02 06:07:59

标签: java collections exception-handling linkedhashset

我知道像

这样的代码
for ( Object o: collection){
    if (condition(i)){
        collection.remove(i);
    }
}

将抛出一个ConcurrentModificationException,我理解为什么:直接修改集合会干扰Iterator跟踪其位置的能力,例如,通过引用一个不再属于其中的元素的引用收集,或导致它跳过刚刚添加的一个。对于像上面这样的代码,这是一个合理的问题,但是,我想写一些类似

的内容
for (Object o: set){// set is an instance of java.util.LinkedHashSet
    if (condition(o)){
        set.remove(other(o));
    }
}

其他(o)在集合的顺序中保证与o“远”。在我的特定实现中,它将永远不会少于47“步”。另外,如果条件(o)为真,则保证所讨论的环路在到达其他(o)所在的位置之前短路。因此,迭代器访问的集合的整个部分与被修改的部分完全分离。此外,LinkedHashSet的特殊优势(快速随机访问插入和删除,保证迭代顺序)似乎特别适合这种精确的操作。

我想我的问题是双重的:首先,考虑到上述限制,这样的操作是否仍然很危险?我认为可能的唯一方法是Iterator值预先提前预加载并缓存,我认为这会提高许多应用程序的性能,但似乎它也会在许多其他应用程序中减少它,因此它是一个来自java.util的通用类的奇怪选择。但也许我错了。谈到缓存等问题,我对效率的直觉常常令人怀疑。其次,假设这种事情,至少在理论上是安全的,有没有办法,没有完全重新实现LinkedHashSet,或牺牲效率,来实现这个操作?我可以告诉Collections忽略我正在修改Set的不同部分的事实,并且像往常一样开展业务吗?我目前的解决方法是首先向中间集合添加元素,然后在循环完成后将它们添加到主集合中,但这样做效率很低,因为它必须将值添加两次。

1 个答案:

答案 0 :(得分:2)

抛出ConcurrentModificationException因为您的收藏集可能无法始终处理删除(或添加)。例如,如果您执行的移除意味着您的LinkedHashSet必须减少/增加底层HashMap占据的空间?它必须进行很多更改,这可能会使迭代器变得无用。

您有两种选择:

使用Iterator来迭代元素并将其删除,例如调用Iterator iter = linkedHashSet.iterator()来获取迭代器,然后按iter.remove()

删除元素

使用java.util.concurrent包下可用的其中一个并发集合,这些集合旨在允许并发修改

This question包含有关使用Iterator

的详细信息 评论后

更新

您可以使用以下模式删除所需的元素,而不会导致ConcurrentModificationException:在循环浏览List元素时,在LinkedHashSet中收集要删除的元素。然后,遍历列表中的每个 toBeDeleted 元素,并将其从LinkedHashSet中删除。