为什么 Iterator.next() 会抛出 ConcurrentModificationException

发布于 2024-11-08 13:51:00 字数 457 浏览 2 评论 0原文

奇怪的是,这一小段代码抛出了上面提到的异常。 另外,看看网上发布的代码,这似乎是正确的:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {

    ArrayList<Integer> arr = new ArrayList<Integer>();

    Iterator i = arr.iterator();

    public void show() {
        arr.add(2);
        arr.add(5);
        arr.add(9);

        while(i.hasNext()){
            System.out.println(i.next());
        }
    }
}

有什么建议吗? 谢谢

Strangly enough, this small piece of code throws the above mentioned Exception.
Also, looking at code posted around the web this seems to be correct:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {

    ArrayList<Integer> arr = new ArrayList<Integer>();

    Iterator i = arr.iterator();

    public void show() {
        arr.add(2);
        arr.add(5);
        arr.add(9);

        while(i.hasNext()){
            System.out.println(i.next());
        }
    }
}

Any advice?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

檐上三寸雪 2024-11-15 13:51:00

此调用:

Iterator i=arr.iterator();

应该在您完成对 ArrayList 的所有写入之后。

因此,在您的代码中,在开始迭代之前执行此操作,如下所示:

Iterator i=arr.iterator();
while(i.hasNext()) {
...
}

This call:

Iterator i=arr.iterator();

should be after you've done all the writes into your ArrayList.

So in your code do this just before you start iterating like this:

Iterator i=arr.iterator();
while(i.hasNext()) {
...
}
丢了幸福的猪 2024-11-15 13:51:00

这是因为您修改了通过 iterator() 获取 Iterator 和调用 next() 之间的支持列表。

迭代器的典型用法是:

for (Iterator<Integer> iter=arr.iterator(); iter.hasNext(); ) {
    Integer element = iter.next();
}

或者更好的是,使用新的 for-each 循环:

for (Integer element: arr) {
}

确保在循环外部对 Collection 执行添加操作。

It's because you've modified the backing list between getting the Iterator via iterator() and calling next().

The typical usage of an Iterator is:

for (Iterator<Integer> iter=arr.iterator(); iter.hasNext(); ) {
    Integer element = iter.next();
}

Or better yet, use the new for-each loop:

for (Integer element: arr) {
}

Make sure to to perform additions to the Collection outside of the loop.

喵星人汪星人 2024-11-15 13:51:00

您在实例化对象 IteratorTest 时定义了 Iterator。然后将一些数据添加到ArrayListarr

您现在已经修改了列表,因此 Iterator 的状态无效。

如果不使用 Iterator 来执行此操作,则无法使用 Iterator 来更改 ArrayList

You are defining the Iterator upon instantiation of your object, IteratorTest. You then add some data to the ArrayList, arr.

You have now modified your list, and thus the Iterator's state is invalid.

You cannot use the Iterator and change the ArrayList without using the Iterator to do it.

皇甫轩 2024-11-15 13:51:00

答案 4 在技术上是正确的,但这并不是因为使用了 for(;;) 或“foreach”循环而不是 while() 循环。这只是迭代器在类中声明的范围而不是方法的问题。首先,让我们看一下 hasNext()next() 这两个方法的行为:

hasNext() 方法只是查询内部游标(指数); next() 实际上使光标前进,因此这是可能引发异常的“修改”。如果您尝试使用在使用 next() 的方法之外声明和分配的迭代器,则代码将在第一个 next() 上引发异常,无论它是 for(;;) 还是 while()

在答案 4 和 8 中,迭代器是在方法内本地声明和使用的。碰巧的是,由于 for(;;) 构造允许在循环执行之前首次声明和分配迭代器(这使得迭代器的作用域为 for(;; ) 并隐式地在方法中,使其“安全”)。我同意 for(;;) 习惯用法在语法上更清晰,并且将范围限制在最低执行级别,完全在 for(;;) 循环内。

答案 8 是正确的,因为迭代器是在方法内部本地分配和使用的。

但是,为了便于讨论,以下使用 while() 语句的方法在语法上是正确的、“安全的”并且从范围和引用的角度来看是不可修改的:

在类定义中的某处
...

ArrayList<String> messageList;

在类构造函数的某处

messageList = new ArrayList<String>(); 

添加一个方法...

public printMessages ( )
{

  Iterator<String> messageIterator = messageList.iterator();

  while (messageIterator.hasNext())
     {
     System.out.println(messageIterator.next());
     }

  System.out.flush();

}

Answer 4 is technically correct, but not because a for(;;) or "for each" loop is used instead of a while() loop. It simply a matter of the Iterator's declared scope within the Class rather than the method. First, let's look at the behavior of the two methods hasNext() and next():

The hasNext() method simply queries an internal cursor (index); next() actually advances the cursor, therefore that is the "modification" that could raise the exception. If you try to use an Iterator declared and assigned outside of the method in which next() is being used, the code will throw an exception on the first next(), regardless if it's a for(;;) or while().

In Answer 4 and 8, the iterator is declared and consumed locally within the method. It just so happens that since the for(;;) construct allows for a first time declaration and assignment of the iterator before the loop executes (which makes the iterator scoped to the for(;;) and implicitly within the method, making it "safe"). I agree that the for(;;) idiom is cleaner syntactically and fences scope at the lowest level of execution, completely within the for(;;) loop.

Answer 8 is correct, because the Iterator is assigned and used locally inside the method.

But, just for sake of the discussion, the following method using a while() statement is syntactically correct, "safe" and non-modifying from a scope and reference perspective:

somewhere in the Class definition
...

ArrayList<String> messageList;

somewhere in the class constructor

messageList = new ArrayList<String>(); 

add a method...

public printMessages ( )
{

  Iterator<String> messageIterator = messageList.iterator();

  while (messageIterator.hasNext())
     {
     System.out.println(messageIterator.next());
     }

  System.out.flush();

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文