子列表抛出的ConcurrentModificationException

时间:2012-01-11 10:18:18

标签: java list

我的代码非常简单:

    List<String> list = new ArrayList<String>();
    String a = "a";
    String b = "b";
    String c = "c";
    String d = "d";

    list.add(a);
    list.add(b);
    list.add(c);

    List<String> backedList = list.subList(0, 2);
    list.add(0, d); 
    System.out.println("2b: " + backedList);

我通过list.add(0,d)得到ConcurrentModificationException异常。所以一般来说,这是因为sublist()。我很困惑,因为在sublist()的情况下,文档说:

  

返回的列表由此列表支持,因此非结构性更改   返回的列表将反映在此列表中,反之亦然

你能解释一下捕获的位置吗?

4 个答案:

答案 0 :(得分:15)

subList是原始列表的简单视图(请参阅here)。您可以改变其中的元素,但不能更改列表的结构。

根据文档,如果您尝试进行结构更改,则subList行为未定义。我想在这个特定的实现中,ConcurrentModificationException被确定为未定义的行为。

  

如果支持列表(即此列表)在结构上以除返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义。 (结构修改是那些改变了这个列表的大小,或以其他方式扰乱它的方式,正在进行的迭代可能会产生不正确的结果。)

答案 1 :(得分:4)

  

返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。 Reference Link

以上陈述绝对正确,但我们必须记住非结构性更改。我想描述两个证明上述陈述的例子 示例1:列表中执行非结构性更改。

public static void main(String[] args) {
        List<String> listArr = new ArrayList<>();
        listArr.add("Delhi");
        listArr.add("Bangalore");
        listArr.add("New York");
        listArr.add("London");

        List<String> listArrSub = listArr.subList(1, 3);

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);

        //Performing Non-Structural Change in list.
        Collections.swap(listArr, 0, 1);

        System.out.println("\nAfter Non-Structural Change...\n");

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);
    }

- 输出信号:

List-: [Delhi, Bangalore, New York, London]
Sub List-: [Bangalore, New York]

After Non-Structural Change...

List-: [Bangalore, Delhi, New York, London]
Sub List-: [Delhi, New York]

解释 - :根据上述Oracle的文档声明,交换操作会反映在两个列表中。

示例2:子列表中执行非结构性更改。

public static void main(String[] args) {
        List<String> listArr = new ArrayList<>();
        listArr.add("Delhi");
        listArr.add("Bangalore");
        listArr.add("New York");
        listArr.add("London");

        List<String> listArrSub = listArr.subList(1, 3);

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);

        //Performing Non-Structural Change in sub list.
        Collections.swap(listArrSub, 0, 1);

        System.out.println("\nAfter Non-Structural Change...\n");

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);
    }

输出 - :

List-: [Delhi, Bangalore, New York, London]
Sub List-: [Bangalore, New York]

After Non-Structural Change...

List-: [Delhi, New York, Bangalore, London]
Sub List-: [New York, Bangalore]

解释 - :根据上述Oracle的文档声明,交换操作反映在两个列表中,但它已在子列表中执行。

正如我们在上述两个例子中看到非结构的变化。现在让我们看看结构更改,如下面的语句所示,这在Oracle的文档中给出。

  

如果支持列表(即此列表)在结构上以除返回列表之外的任何方式进行修改,则此方法返回的列表的语义将变为未定义。 (结构修改是那些改变了这个列表的大小,或以其他方式扰乱它的方式,正在进行的迭代可能会产生不正确的结果。)

示例3:在列表中执行结构更改。

 public static void main(String[] args) {
        List<String> listArr = new ArrayList<>();
        listArr.add("Delhi");
        listArr.add("Bangalore");
        listArr.add("New York");
        listArr.add("London");

        List<String> listArrSub = listArr.subList(1, 3);

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);

        //Performing Structural Change in list.
        listArr.add("Mumbai");

        System.out.println("\nAfter Structural Change...\n");

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);
    }

输出 - :

List-: [Delhi, Bangalore, New York, London]
Sub List-: [Bangalore, New York]

After Structural Change...

List-: [Delhi, Bangalore, New York, London, Mumbai]
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
    at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
    at java.util.AbstractList.listIterator(AbstractList.java:299)
    at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
    at java.util.AbstractCollection.toString(AbstractCollection.java:454)
    at java.lang.String.valueOf(String.java:2982)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at infosys.Research.main(Research.java:26)

解释 - :根据前面提到的Oracle的文档声明,结构修改操作每当抛出java.util.ConcurrentModificationException异常时,如果支持列表(即此列表)是以下方式,此方法返回的列表的语义将变为未定义除了通过返回的列表以外的任何方式进行结构修改。

示例4:子列表中执行结构更改。

public static void main(String[] args) {
        List<String> listArr = new ArrayList<>();
        listArr.add("Delhi");
        listArr.add("Bangalore");
        listArr.add("New York");
        listArr.add("London");

        List<String> listArrSub = listArr.subList(1, 3);

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);

        //Performing Structural Change in sub list.
        listArrSub.add("Mumbai");

        System.out.println("\nAfter Structural Change...\n");

        System.out.println("List-: " + listArr);
        System.out.println("Sub List-: " + listArrSub);
    }

输出 - :

List-: [Delhi, Bangalore, New York, London]
Sub List-: [Bangalore, New York]

After Structural Change...

List-: [Delhi, Bangalore, New York, Mumbai, London]
Sub List-: [Bangalore, New York, Mumbai]

解释 - :结构修改到返回的列表运行良好并完全反映在列表中。

答案 2 :(得分:0)

list.add(0,d)涉及将所有项目移动一个位置并增加列表的大小。这是相当结构性的变化。

答案 3 :(得分:0)

遇到此错误的情况

  • 我有一个列表(原始列表),让我们说100项
  • 按升序排序原始列表
  • 子列表 - &gt;创建子列表(升序有序子列表)
  • 按降序排列原始列表
  • 迭代子列表(升序有序子列表)列表

获得并发修改例外

修复上述情况

  • 我有一个列表(原始列表),让我们说100项
  • 按升序排序
  • 子列表 - &gt;创建子列表(升序有序子列表)
  • 迭代下列(升序有序子列表)列表
  • 按降序排列原始列表