【问题标题】:Java: Can not change list of iteratorsJava:无法更改迭代器列表
【发布时间】:2010-11-13 13:18:21
【问题描述】:

我有一个 ListIterator<PointF> 列表作为类字段。我填写方法grow()。当我尝试使用此列表中的迭代器时,我得到ConcurrentModificationException

ListIterator<ListIterator<PointF>> i = mPoints.listIterator();
while (i.hasNext()) {
    ListIterator<PointF> j = i.next();
    if (j.hasNext())
        PointF tmp = j.next(); // Exception here
}

我不知道为什么这段代码会在任何方法中导致异常除了 grow()

【问题讨论】:

  • 请发布一个简短但完整的程序来演示该问题。
  • @Jon Skeet 问题解决了,我在获取迭代器后修改了我的列表mPoints

标签: java collections iterator


【解决方案1】:

如果底层列表发生变化,之前获取的迭代器会抛出ConcurrentModificationException。所以不要将迭代器存储在实例字段中。

【讨论】:

    【解决方案2】:

    我们可以肯定地说,ConcurrentModificationException 意味着在您调用获取迭代器之后,底层的可迭代对象已被修改。

    这并不总是意味着多线程中的并发;可以通过遍历列表并在循环期间删除元素来轻松触发此异常。因此,如果没有其他线程可能修改它,那么我们可以说当前线程在某个时候修改了迭代器的底层数据结构。

    这里没有足够的代码可以确定,但是您存储迭代器的做法有点可疑。您何时将(内部)迭代器添加到mPoints?如果它们引用的集合在迭代器创建后的任何时间发生了变化,它会在调用时抛出这个异常。因此,只要将迭代器添加到 mPoints 集合,迭代器的数据结构就会有效地锁定以进行更改,但这一点在代码中根本不会很清楚。

    所以我怀疑这是您的问题的根本原因。除非它是短期的(并且通常在单个词法范围内,例如单个方法调用),否则出于您所看到的原因存储 iterators 可能是一个坏主意。存储对底层集合本身的引用可能会更好,然后在上面的代码块中创建迭代器,例如:

    ListIterator<Iterable<PointF>> i = mPoints.listIterator();
    while (i.hasNext()) {
        Iterator<PointF> j = i.next().iterator();
        if (j.hasNext())
            PointF tmp = j.next();
    }
    

    然后,确切的解决方案再次取决于您方法的一般架构。要记住的主要事情是不要长期存储迭代器,因为几乎不可能使这项工作可靠地工作。即使它现在确实有效,它也会在代码的不同部分之间创建一种无形的依赖关系,几乎总是会被实现本应微不足道的更改的人破坏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 2021-07-13
      • 2016-03-16
      • 1970-01-01
      • 2013-05-26
      相关资源
      最近更新 更多