JAVA使用subList實現List的僞分頁

使用前提:當列表頁的數據量比較大,而數據源又不是數據庫的時候(如調用第三方接口),無法支持分頁.但是產品那邊爲了頁面統一,用戶體驗,要實現分頁功能的時候.

話不多說,先上代碼:

/**
     * 處理列表分頁
     * @author zsc
     * @param list 分頁的list
     * @param pageNum 頁碼
     * @param pageSize 每頁條數
     * @return java.util.List<T>
     * @date 2020/1/19 15:46
    **/
    private <T extends Serializable>  List<T> handlerListPage(List<T> list, int pageNum, int pageSize) {
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<T>();
        }
        // 每頁大小不能大於總條數
        pageSize = Math.min(pageSize, list.size());
        // 如果是第一頁 從0開始 到每頁條數+1結束
        int fromIndex = 0;
        int toIndex = fromIndex + pageSize;
        // 不是第一頁
        if (1 != pageNum) {
            fromIndex = (pageNum - 1) * pageSize;
            toIndex = Math.min(fromIndex + pageSize, list.size());
        }
        if (toIndex > list.size() || fromIndex > toIndex) {
            return new ArrayList<T>();
        }
        return list.subList(fromIndex, toIndex);
    }

可以看到上面在處理完分頁參數之後,調用了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 &lt; 0 || toIndex &gt; size ||
     *         fromIndex &gt; toIndex</tt>)
     */
    List<E> subList(int fromIndex, int toIndex);


    public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }
    
    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;
        }

接口內部的文檔描述 Returns a view of the portion of this list between the specified – --返回傳入這個list的指定的一部分視圖. 之後,ArrayList的實現是先校驗了範圍,之後返回了一個SubList對象,給了當前List的默認屬性,入參的範圍.

如果有條件檢索的話,需要先篩選,再分頁像這樣:

/**
     * 處理通用返回數據
     * @author zsc
     * @param list 源list
     * @param param 分頁和條件參數
     * @return com.zijinph.riskcontrol.dto.CommonTaxPageDTO
     * @date 2020/1/21 16:58
    **/
    private CommonTaxPageDTO processCommonResponse(List<CommonTaxDTO> list, CommonTaxPageParam param) {
        CommonTaxPageDTO dto = new CommonTaxPageDTO();
        list = filtrationList(list, param.getCondition());
        dto.setTotalRecords(CollectionUtil.isEmpty(list) ? 0 : list.size());
        dto.setDtoList(handlerListPage(list, param.getPageNum(), param.getPageSize()));
        return dto;
    }
    /**
     * 根據表名篩選集合
     * @author zsc
     * @param list 源list
     * @param condition 條件
     * @return void
     * @date 2020/1/20 18:04
     **/
    private List<CommonTaxDTO> filtrationList(List<CommonTaxDTO> list, String condition) {
        if (!StringUtil.isEmpty(condition)) {
            list = list.stream().filter(item -> condition.equals(item.getDeclarationTableName())).collect(Collectors.toList());
        }
        return list;
    }

總結:

如果是類似的業務場景,像博主這邊需要調大數據接口拿數據,可以先解析出List,存入緩存.之後每次僞分頁和條件檢索都從緩存拿,不然每次做分頁都是重新調用接口,解析json,根據規則取值拼接什麼的,太消耗資源.

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