Array 8: parsing the subList of ArrayList in Alibaba Development Manual

Posted by cwscribner on Sat, 15 Jan 2022 02:06:37 +0100

In the Taishan edition of Alibaba Java development manual, there are two descriptions about subList

What does this mean? Let's analyze:

Let's first look at the simple use of subList:

List<String> bookList = new ArrayList<>();bookList.add("Kwai Ali");bookList.add("promotion increase ");bookList.add("assume CTO");bookList.add("Marry Bai Fumei");bookList.add("Towards the peak of life");​List<String> lqcBookList = bookList.subList(3, 5);​System.out.println(bookList);System.out.println(lqcBookList);

The operation results are shown in the figure below:

[Kwai Ali, promotion increase , assume CTO, Marry Bai Fumei, Towards the peak of life][Marry Bai Fumei, Towards the peak of life]

As can be seen from the running results, subList returns a collection of elements with indexes from fromIndex (included) to toIndex (not included) in bookList.

It is easy to use and easy to understand. However, it should be noted that modifying the original set will affect the subset. If you modify the subset, it will affect the original set.

For example, let's modify the value of an element in the original collection bookList (non structural modification):

     public static void testSubList() {        List<String> bookList = new ArrayList();        bookList.add("Kwai Ali");        bookList.add("promotion increase ");        bookList.add("assume CTO");        bookList.add("Marry Bai Fumei");        bookList.add("Towards the peak of life");​        List<String> lBookList = bookList.subList(2, 5);        System.out.println("Before modification:");        System.out.println("bookList: " + bookList);        System.out.println("lBookList: " + lBookList);        // Modify the value of the original collection booklist Set (2, "CEO also OK"); System.out.println("modified:"); System.out.println("bookList: " + bookList);        System.out.println("lBookList: " + lBookList);    }

Print results:

Before modification: bookList: [Kwai Ali, promotion increase , assume CTO, Marry Bai Fumei, Towards the peak of life]lBookList: [assume CTO, Marry Bai Fumei, Towards the peak of life]After modification: bookList: [Kwai Ali, promotion increase , CEO OK, Marry Bai Fumei, Towards the peak of life]lBookList: [CEO OK, Marry Bai Fumei, Towards the peak of life]

As you can see, we modified the original bookList, and the fruit collection lBookList was also modified. The "being a CTO" was replaced with "being a CEO".

Another one: "modifying the structure of the original set will cause a ConcurrentModificationException exception". What's the matter?

For example, we add an element (structural modification) to the original collection bookList:

   public static void testSubList() {        List<String> bookList = new ArrayList();        bookList.add("Kwai Ali");        bookList.add("promotion increase ");        bookList.add("assume CTO");        bookList.add("Marry Bai Fumei");        bookList.add("Towards the peak of life");​        List<String> lBookList = bookList.subList(2, 5);        System.out.println("Before modification:");        System.out.println("bookList: " + bookList);        System.out.println("lBookList: " + lBookList);        //Add a booklist to the original collection Add ("think a little excited"); System.out.println("modified:"); System.out.println("bookList: " + bookList);        System.out.println("lBookList: " + lBookList);    }

We can see that the exception is thrown when printing the sub list:

Here, although the original list is added successfully, an exception is thrown when printing the sublist.

It should be noted that the above exceptions do not occur when adding elements, but when traversing subsets after adding elements.

What's the reason? Let's look at the source code

First, let's take a look at the comments of the subList method to understand its purpose:

Returns a view of the portion of this list between the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.

In human words, it returns the view of the list part between the specified fromIndex and toIndex.

Then, let's look at its source code:

public List<E> subList(int fromIndex, int toIndex) {
   subListRangeCheck(fromIndex, toIndex, size);
   return new SubList(this, 0, fromIndex, toIndex);
}

You can see that it calls the constructor of SubList class. The source code of the constructor is as follows:

private class SubList extends AbstractList<E> implements RandomAccess {
       private final AbstractList<E> parent;
       private final int parentOffset;
       private final int offset;
       int size;

       SubList(AbstractList<E> parent,
               int offset, int fromIndex, int toIndex) {
           this.parent = parent;
           this.parentOffset = fromIndex;
           this.offset = offset + fromIndex;
           this.size = toIndex - fromIndex;
           this.modCount = ArrayList.this.modCount;
      }
       ····
      }

It can be seen that SubList class is an internal class of ArrayList. A new ArrayList is not recreated in this constructor, but the cursor of the original List is directly used. In other words, the two actually point to the same heap memory space. SubList just adds a new indicator cursor for easy operation. Therefore, modifying one of them will affect the other. This is dangerous in business and can lead to unknown errors, so you can't do it.

summary

The subList method of ArrayList returns a subset (view) of the original set. Non structural modification of the values of the elements of any set will affect each other. When structurally modifying the original set, a ConcurrentModificationException exception will be reported. When structurally modifying the subset, it will affect the original set. Therefore, pay attention to avoid program errors or exceptions.


 


 

Topics: Algorithm