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,根据规则取值拼接什么的,太消耗资源.

发布了5 篇原创文章 · 获赞 7 · 访问量 1333

猜你喜欢

转载自blog.csdn.net/weixin_44138309/article/details/104074087