Java 子列表引发的ConcurrentModificationException

Java 子列表引发的ConcurrentModificationException,java,list,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.subL

我有非常简单的代码:

    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 List=new ArrayList();
字符串a=“a”;
字符串b=“b”;
字符串c=“c”;
字符串d=“d”;
列表.添加(a);
列表.添加(b);
增加(c)项;
List backedList=List.subList(0,2);
列表。添加(0,d);
System.out.println(“2b:+backedList”);
我通过list.add(0,d)得到ConcurrentModificationException异常。一般来说,这是因为sublist()。我很困惑,因为在sublist()的情况下,文档中说:

返回的列表由该列表支持,因此 返回的列表反映在此列表中,反之亦然

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);
    }
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);
    }
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);
    }

您能解释一下捕获点在哪里吗?

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

根据文档,“如果您试图进行结构更改,
子列表
行为未定义。”。我猜在这个特定的实现中,
ConcurrentModificationException
被确定为未定义的行为

如果支持列表(即,此列表)以任何方式(而不是通过返回的列表)进行结构修改,则此方法返回的列表的语义将变得未定义。(结构修改是指更改此列表的大小,或以其他方式干扰列表,使正在进行的迭代可能产生不正确的结果。)

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

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

上述说法绝对正确,但我们必须牢记非结构性变化。我想描述两个例子来证明上述说法。
示例-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);
    }
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);
    }
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);
    }
说明-:根据前面提到的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 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);
    }
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);
    }
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);
    }
解释-:根据前面提到的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);
    }
解释-:根据前面提到的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 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);
    }
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);
    }
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);
    }

解释-:对返回的列表进行结构修改效果良好,并反映在列表中

遇到此错误的场景

  • 我有一份清单(原始清单),比如说100件
  • 按升序对原始列表排序
  • 子列表it->已创建子列表(升序子列表)
  • 按降序排列原始列表
  • 迭代子列表(升序有序子列表)列表
出现并发修改异常

修复上述场景

  • 我有一份清单(原始清单),比如说100件
  • 按升序排序
  • 子列表it->已创建子列表(升序子列表)
  • 迭代子列表(升序有序子列表)列表
  • 按降序排列原始列表

问题在于,向列表中添加元素是一种结构上的改变。正如您提到的@peter,这句话中的相反说法是误导性的,因为正如文档(以及您的代码)稍后解释的那样,在不查看子列表的情况下修改备份列表会引发ConcurrentModificationException,我浪费了一天时间来检查到底出了什么问题,谢谢,这帮助我重新安排了代码中的行。请参阅我在下面添加的答案,以进一步澄清上述评论