子列表抛出的ConcurrentModificationException

pet*_*ter 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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jef*_*ter 17

subList是原始列表的简单视图(见这里).您可以改变其中的元素,但不能更改列表的结构.

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

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


Ash*_*mar 5

返回列表由该列表支持,因此返回列表中的非结构更改会反映在此列表中,反之亦然。参考链接

以上说法绝对正确,但我们必须牢记非结构性变化。我想描述证明上述说法合理的两个例子。
示例1:list中执行非结构更改。

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);
    }
Run Code Online (Sandbox Code Playgroud)

输出-:

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]
Run Code Online (Sandbox Code Playgroud)

说明-:根据上述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);
    }
Run Code Online (Sandbox Code Playgroud)

输出-:

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]
Run Code Online (Sandbox Code Playgroud)

说明-:根据前面提到的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);
    }
Run Code Online (Sandbox Code Playgroud)

输出-:

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)
Run Code Online (Sandbox Code Playgroud)

说明-:根据上述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);
    }
Run Code Online (Sandbox Code Playgroud)

输出-:

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]
Run Code Online (Sandbox Code Playgroud)

说明-:对返回列表的结构修改效果很好,并且完全反映在列表中。