List集合分頁操作

代碼實現

在實際業務代碼中有時在刷數據時需要對集合List進行分批操作,故此總結記錄一下:

for (int i = 0; i < batchList.size(); i += SmsCommonConstants.EduPushVariable.BATCH_NUM) {
int end = i + SmsCommonConstants.EduPushVariable.BATCH_NUM;
      if(end > batchList.size()) {
          end = batchList.size();
      }
      List<SmsBatch> copy = batchList.subList(i, end);

      if(CollectionUtils.isNotEmpty(copy)){
          initDataMapper.insertBatch(copy);

          List<String> batchNos = copy.stream().map(m -> m.getBatchNo()).collect(Collectors.toList());
          updateBatchData(batchNos);
      }
  }

爲什麼阿里巴巴要求謹慎使用ArrayList中的subList方法

關於集合類,《阿里巴巴Java開發手冊》中其實還有另外一個規定:
在這裏插入圖片描述
爲什麼會有這個建議呢?我們來看看源碼就一目瞭然了

在這裏插入圖片描述
subList是List接口中定義的一個方法,該方法主要用於返回一個集合中的一段、可以理解爲截取一個集合中的部分元素,他的返回值也是一個List。

如果我們改動下代碼,將subList的返回值強轉成ArrayList試一下:

public static void main(String[] args) {
    List<String> names = new ArrayList<String>() {{
        add("Hollis");
        add("hollischuang");
        add("H");
    }};

    ArrayList subList = (ArrayList) names.subList(0, 1);
    System.out.println(subList);
}

以上代碼將拋出異常:

Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList

不只是強轉成ArrayList會報錯,強轉成LinkedList、Vector等List的實現類同樣也都會報錯。

那麼,爲什麼會發生這樣的報錯呢?我們接下來深入分析一下。

底層原理

首先我麼來看一下subList方法返回的是什麼,JDK源碼裏面是這樣描述的:

Returns a view of the portion of this list between the specified

也就是說subList 返回是一個視圖,那麼什麼叫做視圖呢?

看源碼可以看出來這個方法返回了一個SubList,這個類是ArrayList中的一個內部類。

SubList這個類中單獨定義了set、get、size、add、remove等方法。

當我們調用subList方法的時候,會通過調用SubList的構造函數創建一個SubList,那麼看下這個構造函數做了哪些事情:
在這裏插入圖片描述
可以看到,這個構造函數中把原來的List以及該List中的部分屬性直接賦值給自己的一些屬性了。

也就是說,SubList並沒有重新創建一個List,而是直接引用了原有的List(返回了父類的視圖),只是指定了一下他要使用的元素的範圍而已(從fromIndex(包含),到toIndex(不包含))。

所以,爲什麼不能講subList方法得到的集合直接轉換成ArrayList呢?因爲SubList只是ArrayList的內部類,他們之間並沒有繼承關係,故無法直接進行強制類型轉換。

  • 當我們嘗試通過set方法,改變subList中某個元素的值得時候,我們發現,原來的那個List中對應元素的值也發生了改變。

  • 同理,如果我們使用同樣的方法,對sourceList中的某個元素進行修改,那麼subList中對應的值也會發生改變

  • 我們嘗試對subList的結構進行改變,即向其追加元素,那麼得到的結果是sourceList的結構也同樣發生了改變

  • 我們嘗試對sourceList的結構進行改變,即向其追加元素,結果發現拋出了ConcurrentModificationException。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章