我正在迭代JRE Collection
,它强制执行fail-fast迭代器概念,因此如果ConcurrentModificationException
在迭代时被修改,则抛出Collection
,而不是使用Iterator.remove()
方法。但是,如果对象满足条件,我需要删除对象的“逻辑伙伴”。从而防止合作伙伴被处理。我怎样才能做到这一点?也许为此目的使用更好的收集类型?
实施例
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
感谢。
答案 0 :(得分:9)
这不是集合的错,它就是你使用它的方式。在迭代中途修改集合会导致此错误(这是一件好事,因为迭代通常无法明确地继续)。
编辑:重新阅读问题后,这种方法将无效,但我将其留在这里作为一般案例中如何避免此问题的示例。
你想要的是这样的:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
如果您通过Iterator本身删除对象,它会知道删除并且一切都按预期工作。请注意,虽然我认为所有标准集合在这方面都能很好地工作,但是迭代器不是必需来实现remove()方法,所以如果你无法控制myCollection
的类(从而返回的迭代器的实现类)你可能需要在那里加入更多的安全检查。
另一种方法(比如说,如果你不能保证迭代器支持remove()
而你需要这个功能)就是创建一个 copy 集合来迭代,然后删除来自原始集合的元素。
编辑:您可以使用后一种技术来实现您想要的功能,但是您最终还是会回到迭代器首先抛出异常的原因:什么如果删除尚未到达的元素,迭代会怎样?删除(或不删除)当前元素是相对明确定义的,但是您要谈论删除当前元素的伙伴,我认为它可能位于iterable中的随机点。由于没有明确的方法可以处理这个问题,因此您需要自己提供某种形式的逻辑来应对这种情况。在这种情况下,我倾向于在迭代期间创建和填充新集合,然后在最后将其分配给myCollection
变量。如果无法做到这一点,那么跟踪要删除的合作伙伴元素并调用myCollection.removeAll
将是最佳选择。
答案 1 :(得分:8)
您想要从列表中删除项目并继续在同一列表上进行迭代。您是否可以实施两步解决方案,在步骤1中,您收集要在临时收集中删除的项目,并在步骤2中识别它们后删除它们?
答案 2 :(得分:3)
一些想法(取决于集合中两个对象之间的关系到底):
答案 3 :(得分:1)
您可以尝试先找到要删除的所有项目,然后在处理完整个列表后删除它们。在找到它们时跳过已删除的项目。
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);
答案 4 :(得分:1)
CopyOnWriteArrayList可以做你想要的。
答案 5 :(得分:0)
为什么不使用所有原始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...
}
}
答案 6 :(得分:0)
最好的答案是第二个,使用迭代器。