我知道这样的代码
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或牺牲效率之外,还有什么方法可以实现这一操作吗?我能不能让集合忽略这样一个事实,那就是我正在修改集合的另一个部分,然后照常进行它的工作。我目前的工作是先将元素添加到中间集合中,然后在循环完成后将它们添加到主集合中,但这是效率低下的,因为它必须将值添加两次。
发布于 2017-02-01 22:20:03
引发ConcurrentModificationException
是因为您的集合可能无法在任何时候处理删除(或添加)。例如,如果您执行的删除意味着您的LinkedHashSet
必须减少/增加底层HashMap
在幕后占用的空间呢?它需要做大量的更改,这可能会使迭代器变得无用。
你有两个选择:
使用Iterator
迭代并删除元素,例如调用Iterator iter = linkedHashSet.iterator()
获取迭代器,然后通过iter.remove()
删除元素
使用java.util.concurrent
包下可用的并发集合之一,该集合旨在允许并发修改
This question包含关于使用Iterator
的详细信息。
在评论后更新:
您可以使用下面的模式来删除您想要的元素,而不会导致ConcurrentModificationException
:在循环遍历LinkedHashSet
元素时,收集您希望在List
中删除的元素。然后,循环遍历列表中的每个toBeDeleted元素,并将其从LinkedHashSet
中删除。
https://stackoverflow.com/questions/41995278
复制相似问题