日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java|List.subList踩坑小記

很久以前在使用 Java 的 List.subList 方法時踩過一個坑,當(dāng)時記了一條待辦,要寫一寫這事,今天完成它。

我們先來看一段代碼:

// 初始化 list 為 { 1, 2, 3, 4, 5 }
List list = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
    list.add(i);
}

// 取前 3 個元素作為 subList,操作 subList
List subList = list.subList(0, 3);
subList.add(6);

System.out.println(list.size());

輸出是 5 還是 6?

沒踩過坑的我,會回答是 5,理由是:往一個 List 里加元素,關(guān)其它 List 什么事?

而掉過坑的我,口中直呼 666。

好了不繞彎子,我們直接看下 List.subList 方法的注釋文檔:

/**
 * Returns a view of the portion of this list between the specified
 * fromIndex, inclusive, and toIndex, exclusive.  (If
 * fromIndex and toIndex are equal, the returned list is
 * empty.)  The returned list is backed by this list, so non-structural
 * changes in the returned list are reflected in this list, and vice-versa.
 * The returned list supports all of the optional list operations supported
 * by this list.

* * This method eliminates the need for explicit range operations (of * the sort that commonly exist for arrays). Any operation that expects * a list can be used as a range operation by passing a subList view * instead of a whole list. For example, the following idiom * removes a range of elements from a list: *

{@code
 *      list.subList(from, to).clear();
 * }
* Similar idioms may be constructed for indexOf and * lastIndexOf, and all of the algorithms in the * Collections class can be applied to a subList.

* * 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.) * * @param fromIndex low endpoint (inclusive) of the subList * @param toIndex high endpoint (exclusive) of the subList * @return a view of the specified range within this list * @throws IndexOutOfBoundsException for an illegal endpoint index value * (fromIndex < 0 || toIndex > size || * fromIndex > toIndex) */ List subList(int fromIndex, int toIndex);

這里面有幾個要點(diǎn):

subList 返回的是原 List 的一個 視圖,而不是一個新的 List,所以對 subList 的操作會反映到原 List 上,反之亦然;

如果原 List 在 subList 操作期間發(fā)生了結(jié)構(gòu)修改,那么 subList 的行為就是未定義的(實際表現(xiàn)為拋異常)。

第一點(diǎn)好理解,看到「視圖」這個詞相信大家就都能理解了。我們甚至可以結(jié)合 ArrayList 里的 SubList 子類源碼進(jìn)一步看下:

private class SubList extends AbstractList implements RandomAccess {
    private final AbstractList parent;
    // ...

    SubList(AbstractList parent,
            int offset, int fromIndex, int toIndex) {
        this.parent = parent;
        // ...
        this.modCount = ArrayList.this.modCount;
    }

    public E set(int index, E e) {
        // ...
        checkForComodification();
        // ...
        ArrayList.this.elementData[offset + index] = e;
        // ...
    }

    public E get(int index) {
        // ...
        checkForComodification();
        return ArrayList.this.elementData(offset + index);
    }

    public void add(int index, E e) {
        // ...
        checkForComodification();
        parent.add(parentOffset + index, e);
        this.modCount = parent.modCount;
        // ...
    }

    public E remove(int index) {
        // ...
        checkForComodification();
        E result = parent.remove(parentOffset + index);
        this.modCount = parent.modCount;
        // ...
    }

    private void checkForComodification() {
        if (ArrayList.this.modCount != this.modCount)
            throw new ConcurrentModificationException();
    }

    // ...
}

可以看到幾乎所有的讀寫操作都是映射到 ArrayList.this、或者 parent(即原 List)上的,包括 size、add、remove、set、get、removeRange、addAll 等等。

第二點(diǎn),我們在文首的示例代碼里加上兩句代碼看現(xiàn)象:

list.add(0, 0);
System.out.println(subList);

System.out.println 會拋出異常 java.util.ConcurrentModificationException。

我們還可以試下,在聲明 subList 后,如果對原 List 進(jìn)行元素增刪操作,然后再讀寫 subList,基本都會拋出此異常。

因為 subList 里的所有讀寫操作里都調(diào)用了 checkForComodification(),這個方法里檢驗了 subList 和 List 的 modCount 字段值是否相等,如果不相等則拋出異常。

modCount 字段定義在 AbstractList 中,記錄所屬 List 發(fā)生 結(jié)構(gòu)修改 的次數(shù)。結(jié)構(gòu)修改 包括修改 List 大小(如 add、remove 等)、或者會使正在進(jìn)行的迭代器操作出錯的修改(如 sort、replaceAll 等)。

好了小結(jié)一下,這其實不算是坑,只是 不應(yīng)該僅憑印象和猜測,就開始使用一個方法,至少花一分鐘認(rèn)真讀完它的官方注釋文檔。


當(dāng)前標(biāo)題:Java|List.subList踩坑小記
分享鏈接:http://www.5511xx.com/article/djshihh.html