成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java|List.subList 踩坑小記

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

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

我們先來看一段代碼:

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

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

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

輸出是 5 還是 6?

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

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

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

/**
 * Returns a view of the portion of this list between the specified
 * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive.  (If
 * <tt>fromIndex</tt> and <tt>toIndex</tt> 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.<p>
 *
 * 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:
 * <pre>{@code
 *      list.subList(from, to).clear();
 * }</pre>
 * Similar idioms may be constructed for <tt>indexOf</tt> and
 * <tt>lastIndexOf</tt>, and all of the algorithms in the
 * <tt>Collections</tt> class can be applied to a subList.<p>
 *
 * The semantics of the list returned by this method become undefined if
 * the backing list (i.e., this list) is <i>structurally modified</i> 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
 *         (<tt>fromIndex < 0 || toIndex > size ||
 *         fromIndex > toIndex</tt>)
 */
List<E> subList(int fromIndex, int toIndex);

這里面有幾個要點:

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

如果原 List 在 subList 操作期間發生了結構修改,那么 subList 的行為就是未定義的(實際表現為拋異常)。

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

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

    SubList(AbstractList<E> 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 等等。

第二點,我們在文首的示例代碼里加上兩句代碼看現象:

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

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

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

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

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

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

責任編輯:趙寧寧 來源: 悶騷的程序員
相關推薦

2021-06-26 15:31:25

Dubbo應用級服務

2024-04-02 08:41:10

ArrayListSubList場景

2023-01-18 23:20:25

編程開發

2020-09-15 08:46:26

Kubernetes探針服務端

2023-02-20 08:11:04

2021-10-28 19:10:02

Go語言編碼

2017-05-05 08:12:51

Spark共享變量

2015-03-24 16:29:55

默認線程池java

2021-09-03 11:15:18

場景sql配置

2024-04-10 08:39:56

BigDecimal浮點數二進制

2024-04-01 08:05:27

Go開發Java

2021-05-27 22:46:00

Nacos Clien版本Nacos

2017-07-17 15:46:20

Oracle并行機制

2021-10-15 06:49:37

MySQL

2022-11-18 07:34:12

Docker項目目錄

2024-10-09 08:09:11

2025-05-27 01:55:00

MySQL數據庫工具鏈

2024-03-13 13:10:48

JavaInteger緩存

2023-06-30 08:10:14

JavaBigDecimal

2025-04-29 10:17:42

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品真实国产乱文在线 | 99成人在线视频 | 伊人网91| 成人精品一区二区三区 | 亚洲精品黑人 | 久久99精品久久久久婷婷 | 国产精品二区三区在线观看 | 天天操天天干天天透 | 国产精品 亚洲一区 | 国产精品天堂 | 91精品国产91久久久久久吃药 | 亚洲国产精品久久久 | 欧美日韩一卡 | 国产综合在线视频 | 国产精品美女一区二区 | 日本 欧美 国产 | 亚洲久久一区 | 亚洲视频国产 | 欧美11一13sex性hd | 久草精品视频 | 男人天堂网址 | 国内在线视频 | 亚洲第一成人av | 国产美女黄色片 | 国产福利资源在线 | 亚洲精品久久久久久一区二区 | 日韩一级二级片 | 亚洲精品免费在线 | 久久国产亚洲 | 日本免费一区二区三区视频 | 国产成人aⅴ | 午夜三区 | 午夜综合 | 精品乱子伦一区二区三区 | 日韩成人 | av特级毛片 | 成人乱人乱一区二区三区软件 | 午夜天堂| 久久久久成人精品免费播放动漫 | 日韩精品中文字幕一区二区三区 | 91精品久久久久久久久 |