繁体   English   中英

如何在迭代Collection时安全地从Collection中删除其他元素

[英]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中识别它们后将其删除?

一些想法(这取决于集合中两个对象之间的关系到底是什么):

  1. 以对象为键,伙伴为值的Map。
  2. 一个CopyOnWriteArrayList,但是当你击中伙伴时你必须注意
  3. 将副本复制到另一个Collection对象中,并迭代一个,删除另一个。 如果这个原始集合可以是一个集合,那么这将有助于删除。

您可以先尝试找到要删除的所有项目,然后在处理完整个列表后删除它们。 在找到它们时跳过已删除的项目。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM