0

我有以下问题:

鉴于:

public class A{
    Collection<B> elements = new ArrayList<B>();
}

public class B{
    Collection<B> linkedElements = new ArrayList<B>();
}

linkedElements 的所有元素也都属于元素。我希望每次从元素集合中删除一个元素时,它的链接元素也会从该集合中删除。我尝试将观察者附加到 Iterator.remove 操作并在那里触发从元素列表中删除linkedElements,但由于逻辑本身,我总是遇到 ConcurrentModificationException。

更新:这是导致错误的代码:

public class A{
 Collection<B> elements = new ArrayList<B>(){
    public Iterator<B> iterator() {
        return new ProxyIterator(super.iterator());
    };

  private class ProxyIterator implements Iterator{

    Iterator it;

    Object lastObject;

    public ProxyIterator(Iterator proxied){
        it = proxied;
    }

    @Override
    public boolean hasNext() {
        return it.hasNext();
    }

    @Override
    public Object next() {
        return lastObject = it.next();
    }

    @Override
    public void remove() {
        it.remove()
        for (B linkedElement : ((B)lastObject).getlinkedElements()) {
            A.this.getElements().remove(linkedElement);
        }
    }

  }
}

使用此代码,只需调用 aA.getElements().clear()将触发 a ConcurrentModificationException... 并且没关系,因为我正在从元素列表中删除所有链接的元素,同时删除一个元素。这就是为什么我需要另一种方法。

4

1 回答 1

1

这是因为您在迭代数组时正在修改数组。来自 ArrayList 的 javadocs:

此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

因此,一旦您A.this.getElements().remove(linkedElement);在 remove 方法中执行此操作,您现在只是通过迭代器it的“remove”方法以外的方式对列表进行了结构修改,这意味着迭代器将抛出 CME。

处理这个可能会很棘手。我可以临时想到一些选项,所有这些选项都有复杂性:

  • 切换到CopyOnWriteArrayList,因为它的迭代器是故障安全的。缺点是您的迭代器可能仍会显示以前删除的项目。(另一方面,无论如何,您都必须应对这种风险,因为您也可能已经迭代过您要删除的任何内容的子节点。)如果这对您有用,那么这几乎肯定是最简单和最可靠的选项。
  • 在 for 循环之后remove,替换it为您手动前进到正确位置的新迭代器。如果您的列表允许重复项,则很难做到。
  • 重新实现 ArrayList.Iterator; 在您的remove方法中,您可以跟踪所做的更改并适当地更新迭代器。

最后,作为最后一个问题/警告-您是否希望此遍历是递归的?现在,如果你有元素 Foo 链接到 Bar,Bar 链接到 Baz,从迭代器中删除 Foo 会导致 Bar 被删除,但是没有任何东西会删除 Baz。(而如果您先删除 Bar,那么 Baz 将被删除。)通常,如果您想修改 a 的删除行为Collection,最好这样做List.remove而不是Iterator.remove.

于 2013-05-23T21:47:40.617 回答