Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentModificationException thrown by sublist [duplicate]

Tags:

java

list

I have very simple code:

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

And I get ConcurrentModificationException exception by list.add(0, d). So in general, it's because of sublist(). I'm very confused, because in case of sublist() the documentation says:

The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa.

Could you explain me where the catch is?

like image 824
peter Avatar asked Jan 11 '12 10:01

peter


2 Answers

The subList is simple a view of the original list (see here). You are allowed to mutate elements within it but not change the structure of the list.

According to the documentation, subList behaviour is undefined if you try to make structural changes. I guess in this particular implementation, ConcurrentModificationException was decided as the undefined behaviour.

The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

like image 117
Jeff Foster Avatar answered Nov 01 '22 21:11

Jeff Foster


The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. Reference Link

Above statement is absolutely correct but we have to keep in mind non-structural change. I would like to depict two examples justifying above statement.
Example-1: Performing Non-Structural change in 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);
    }

Output-:

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]

Explanation-: As per aforementioned Oracle's documentation statement, swapping operation is reflected in both the lists.

Example-2: Performing Non-Structural change in sub 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 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);
    }

Output-:

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]

Explanation-:As per aforementioned Oracle's documentation statement, swapping operation is reflected in both the lists however it has been performed on sub list.

As we have seen Non-Structural changes in the aforementioned two examples. Now let's see Structural changes as per below statement which is given in the Oracle's documentation.

The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

Example-3: Performing Structural change in 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 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);
    }

Output-:

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)

Explanation-:As per aforementioned Oracle's documentation statement, structural modification operation is throwing java.util.ConcurrentModificationException exception whenever The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list.

Example-4: Performing Structural change in sub 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 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);
    }

Output-:

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]

Explanation-: Structural modification to returned list is working well and reflecting in the list altogether.

like image 30
Ashish Kumar Avatar answered Nov 01 '22 21:11

Ashish Kumar