Java List抛出ConcurrentModificationException,但set不抛出ConcurrentModificationException?

Java List抛出ConcurrentModificationException,但set不抛出ConcurrentModificationException?,java,list,arraylist,set,hashset,Java,List,Arraylist,Set,Hashset,我有下面两个java类 import java.util.*; public class ArrayListTest032 { public static void main(String[] ar) { List<String> list = new ArrayList<String>(); list.add("core java"); list.add("php"); list.add("j2e

我有下面两个java类

import java.util.*;

public class ArrayListTest032 {
    public static void main(String[] ar) {
        List<String> list = new ArrayList<String>();
        list.add("core java");
        list.add("php");
        list.add("j2ee");
        list.add("struts");
        list.add("hibernate");

        Iterator<String> itr = list.iterator();

        while (itr.hasNext()) {
            System.out.println(itr.next());
        }
        list.remove("php");

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

    }
}
这是预期的,因为我在迭代时修改列表。但在下面的java类中,相同的逻辑由集合族执行

import java.util.*;

public class HashSetTest021 {
    public static void main(String[] ar) {
        Set<String> set = new HashSet<String>();
        set.add("core java");
        set.add("php");
        set.add("j2ee");
        set.add("struts");
        set.add("hibernate");

        Iterator<String> itr = set.iterator();

        while (itr.hasNext()) {
            System.out.println(itr.next());
        }
        set.remove("php");

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

    }
}
没有任何ConcurrentModificationException

我只是想知道为什么在
list
family的情况下,同一段代码会抛出ConcurrentModificationException,而在
set
family的情况下,却没有任何ConcurrentModificationException

公共静态void main(String[]ar){
 public static void main(String[] ar) {
            List<String> list = new ArrayList<String>();
            list.add("core java");
            list.add("php");
            list.add("j2ee");
            list.add("struts");
            list.add("hibernate");

            Iterator<String> itr = list.iterator();

            while (itr.hasNext()) {
                System.out.println(itr.next());
            }
            list.remove("php");

          /*  while (itr.hasNext()) {
                System.out.println(itr.next());
            }*/

        }

problem in itr object.it holds the list object reference
列表=新的ArrayList(); 添加(“核心java”); 添加(“php”); 添加(“j2ee”); 列表。添加(“struts”); 添加(“休眠”); 迭代器itr=list.Iterator(); while(itr.hasNext()){ System.out.println(itr.next()); } 列表。删除(“php”); /*while(itr.hasNext()){ System.out.println(itr.next()); }*/ } itr对象中存在问题。它保存列表对象引用
这是一种“倒退”行为,因为迭代器一旦被完全遍历,就不可重用,也就是说,当到达列表末尾时,它们的
hasNext
方法应该返回false

但在本例中,
ArrayList.iterator
返回的迭代器是一个内部实现类,其代码为
hasNext
,如下所示:

public boolean hasNext() {
    return cursor != size;
}
public final boolean hasNext() {
    return next != null;
}
因此,当您在第二个循环中调用
hasNext
时,它(错误地)指示有更多项要迭代,因为您在第一次迭代后执行了一个更改列表大小的操作。从语义上讲,在到达列表末尾后,您应该不能继续迭代列表中的项,但是由于这个实现细节,它允许您继续执行第二个while循环。当然,此时,由于在支持列表中所做的更改,您会得到一个并发修改异常

另一方面,哈希集使用的迭代器的
hasNext
实现如下:

public boolean hasNext() {
    return cursor != size;
}
public final boolean hasNext() {
    return next != null;
}
迭代完成后,此实现恰好不易受到哈希集修改的影响,因此
hasNext
方法的性能更好。

从读取for迭代器开始。它是否在任何地方提到了
ConcurrentModificationException

现在,阅读JavaDoc,并注意以下内容(重点添加):

当不允许对对象进行修改时,检测到对象同时修改的方法可能会引发此异常

现在仔细看看你的代码。您的
while
循环遍历集合的所有元素(即使第一个示例的输出没有指出这一点,这告诉我要么您编辑了输出,要么这不是您的实际代码)。在删除元素时,没有更多的项需要迭代,因此第二个循环应该总是立即退出


因此,结论是列表迭代器的实现者选择了在没有更多元素可迭代时抛出该异常,而集合迭代器的实现者选择了不抛出该异常。考虑到规范,这两种情况都是完全可以接受的。

这是实现中的一个区别:数组列表返回的迭代器即使位于末尾也会检测并发修改,因为它检查长度;另一方面,
HashSet
TreeSet
LinkedList
的迭代器没有检测到这种情况,因为它们在检查并发修改之前检查是否位于末尾。文档允许迭代器不进行并发修改,因此这两种方法都是有效的


如果您对集合执行任何操作(除了通过迭代器),则Hashset可以抛出ConcurrentModificationException。然而,围绕itertor的快速失效行为有很多启发式方法,目的是尽可能地完成迭代。JavaDocs似乎非常清楚它的行为

当我们使用第一个循环遍历列表时 迭代器itr=set.Iterator()

游标值和大小将变为相同。游标包含已遍历元素总数的值,列表遍历的hashNext()方法中包含如下代码:

  public boolean hasNext() {
            return cursor != size;
        }
所以在first while循环cursor==size之后。但是在从列表中删除元素之后,size变为(originalSize-1)。所以对于next while循环,它进入while和itr.next()方法内部,检查modcount修改并抛出ConcurrentModificationException


如果设置,则检查下一步!=每个itr.hasnext()都为null在遍历第一个while循环后,next变为null。从集合中删除元素不会影响next值为null,itr.hasNext将next==null返回为true,因此它不会进入while循环内部检查modcount修改。因此它不会引发ConcurrentModification异常。

那么为什么集合不会引发异常呢。您可以从输出堆栈跟踪中检查这两个类,很明显,在调用迭代器next()函数时会出现异常。如果您想知道迭代器是如何检查修改的,它的实现存在于AbstractList类中,在AbstractList类中定义了一个int变量modCount,该变量提供了列表大小更改的次数。确定了吗?如果是set-family?@Real-添加了哈希集实现的详细信息。我在上述代码中添加了相同的类,您可以自己运行代码并检查输出。@Real-是的,我运行了它,输出显示为“hibernate”,而您的帖子没有显示。但事实上,与其让你的短裤因为一个附加的c而扭曲
  public boolean hasNext() {
            return cursor != size;
        }