[英]How to safely remove other elements from a Collection while iterating through the Collection
我正在迭代一个强制执行故障快速迭代器概念的JRE Collection
,因此如果在迭代时修改Collection
则抛出ConcurrentModificationException
,而不是使用Iterator.remove()
方法。 但是,如果对象满足条件,我需要删除对象的“逻辑伙伴”。 从而防止合作伙伴被处理。 我怎样才能做到这一点? 也许为此目的使用更好的收集类型?
例。
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
谢谢。
这不是系列的错,它是你使用它的方式。 在迭代中途修改集合会导致此错误(这是一件好事,因为迭代通常无法明确地继续)。
编辑 :重新阅读问题后,这种方法将无效,但我将其留在这里作为一般情况下如何避免此问题的示例。
你想要的是这样的:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
如果你通过迭代器本身删除对象,它就会知道删除对象,一切都按照你的预期运行。 请注意,虽然我认为所有标准集合在这方面都能很好地工作,但是迭代器不需要实现remove()方法,所以如果你无法控制myCollection
的类(以及返回的迭代器的实现类),你可能需要在那里进行更多的安全检查。
另一种方法(例如,如果您不能保证迭代器支持remove()
并且您需要此功能)是创建要迭代的集合的副本 ,然后从原始集合中删除元素。
编辑 :你可以使用后一种技术来实现你想要的,但是你最终还是会回到迭代器首先抛出异常的原因: 如果你删除了一个没有的元素,迭代应该做什么到了吗? 删除(或不删除)当前元素是相对明确定义的,但是你谈到删除当前元素的伙伴 ,我认为它可以在迭代中的随机点。 由于没有明确的方法可以处理这个问题,因此您需要自己提供某种形式的逻辑来应对这种情况。 在这种情况下,我倾向于在迭代期间创建和填充新集合,然后在最后将其分配给myCollection
变量。 如果这是不可能的,那么跟踪要删除的伙伴元素并调用myCollection.removeAll
就可以了。
您想要从列表中删除项目并继续在同一列表上进行迭代。 您是否可以实施两步解决方案,在步骤1中,您收集要在临时收集中删除的项目,并在步骤2中识别它们后将其删除?
一些想法(这取决于集合中两个对象之间的关系到底是什么):
您可以先尝试找到要删除的所有项目,然后在处理完整个列表后删除它们。 在找到它们时跳过已删除的项目。
myCollection<BusinessObject>
List<BusinessObject> deletedObjects = new ArrayList(myCollection.size());
for (BusinessObject anObject : myCollection)
{
if (!deletedObjects.contains(anObject))
{
if (someConditionIsTrue)
{
deletedObjects.add(anObjectsPartner);
}
}
}
myCollection.removeAll(deletedObjects);
CopyOnWriteArrayList将执行您想要的操作。
为什么不使用所有原始BusinessObject的集合,然后使用一个与它们相关联的单独类(例如Map)(即创建合作伙伴)? 将它们作为复合元素放在它自己的类中,以便在删除Business对象时始终可以删除Partner。 每次需要从Collection中删除BusinessObject时,不要让调用者负责。
IE
class BusinessObjectCollection implements Collection<BusinessObject> {
Collection<BusinessObject> objects;
Map<BusinessObject, BusinessObject> associations;
public void remove(BusinessObject o) {
...
// remove from collection and dissasociate...
}
}
最好的答案是第二个,使用迭代器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.