我想了解 Java 的迭代器。为什么它们被设计为抛出并发修改异常?在 C++ STL 中,您可以迭代容器并随时修改内容,但为什么不能在 Java 中进行呢?
编辑:更正的问题。被错误地构图。
这是一个示例,说明为什么在迭代列表时尝试修改列表时迭代器会抛出。
假设您的迭代器是使用索引实现的,例如ArrayList
:假设您的迭代器现在指向位置 3 List
。现在你在 position 添加一个元素1
。迭代器不知道你做了什么改变,所以它仍然指向位置 3,但是位置 3 现在保存了曾经在位置 2 的元素,因为一切都被向下移动了。所以你的迭代器现在将访问一个元素两次!那很糟。
所以规则是,当您在迭代列表时修改列表时,您必须从迭代器本身这样做,因此迭代器知道如何使其位置与对列表的修改保持同步。如果您在不通过迭代器的情况下修改列表,迭代器会抛出 aConcurrentModificationException
而不是默默地被破坏,例如多次访问一个元素。
您可以在迭代集合时修改它。您只需要使用Iterator.remove()即可。
例如,如果另一个线程在迭代期间修改了集合,则可能会引发ConcurrentModificationException 。这比未定义的行为更可取。
Java 迭代器不是线程化的。可能存在多个线程,并且迭代器可能在这些线程中表现良好。
我不会解释为什么它们是这样设计的,而是让你知道这个小秘密:
如果您在迭代期间从列表中删除,您将得到一个并发异常。如果您在迭代期间删除使用迭代器,您可能会因为某些其他原因而获得并发异常。
像这样的东西
for(Iterator<?> iter = list.getIterator(); iter.hasNext(); )
{
MyClass c = iter.getNext();
if( //i need to remove this instance)
iter.remove(iter);
}
将调用包装起来synchronized
或将变量标记为volatile
可能会帮助您避免并发修改,因为这些会同步对对象的访问,从而防止您同时从多个源访问它。
或使用 [COW 列表] ( http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CopyOnWriteArrayList.html )
我今天似乎无法掌握如何在 SO 上链接东西....