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

package org.wzj.common; import java.io.IOException; import java.net.URLDecoder; import java.net.URLEncoder; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.tagext.BodyContent; import javax.servlet.jsp.tagext.BodyTagSupport; public class FenyeTag extends BodyTagSupport { private static final long serialVersionUID = 1L; private String html; private String exname; private String target = ""; //链接所响应的框架窗口 private String cssClass; //样式名 private String action; //链接 private Integer pageCount; //总页数 private Integer current; //当前页码 private Integer showCount = 10; //在页面上显示多少个链接 private Integer spanWidth = 50; public static final String TEXT = "background-color:blue;color:white;"; public int doEndTag(){ BodyContent body = this.getBodyContent(); JspWriter out = body.getEnclosingWriter(); html = "<div id='fydiv'>"; int start = 1; if ( pageCount > 0 ){ if ( current > pageCount ){ current = pageCount; } if ( current < 1 ){ current = 1; } if ( exname == null || exname.equals("")){ html += "<a href='" + action + "?pageNum=1' target='" + target + "' class='" + cssClass + "' }else{ html += "a href=' target='" + target + "' class='" + cssClass + "' } html += "'>首页</a>"; if ( current > showCount - showCount/3 ){ start = start + showCount/3*(current/(showCount/3)-2); } if ( current < showCount - showCount/3 ){ start = 1; } int rcount = 1; //////////////////////////// for ( int i = 1; i <= pageCount; i ++ ){ if ( i >= start ){ //起始页码 if ( rcount <= showCount ){ //只显示showCount个链接 if ( exname == null || exname.equals("")){ html += "  <a href='" + action + "?pageNum=" + i + "' target='" + target + "' class='" + cssClass + "' }else{ html += "  a href=' target='" + target + "' class='" + cssClass + "' } if ( current == i ){ html += TEXT; } html += "'>" + i + "</a>  "; } if ( i < pageCount && rcount == showCount ){ html += "...  "; } rcount ++; } } //////////////////////////// if ( exname == null || exname.equals("")){ html += "<a href='" + action + "?pageNum=" + pageCount + "' target='" + target + "' class='" + cssClass + "' }else{ html += "a href=' target='" + target + "' class='" + cssClass + "' } html += "'>末页</a>"; html += "    第<span + current + "</span>页 共<span + pageCount + "</span>页"; } html += "</div>"; try { out.print(html); out.flush(); body.clearBody(); } catch (IOException ex) { ex.printStackTrace(); } return this.EVAL_PAGE; } public String getExname() { return exname; } public void setExname(String exname) { this.exname = exname; } public String getTarget() { return target; } public void setTarget(String target) { this.target = target; } public String getCssClass() { return cssClass; } public void setCssClass(String cssClass) { this.cssClass = cssClass; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public Integer getPageCount() { return pageCount; } public void setPageCount(Integer pageCount) { this.pageCount = pageCount; } public Integer getCurrent() { return current; } public void setCurrent(Integer current) { this.current = current; } public Integer getShowCount() { return showCount; } public void setShowCount(Integer showCount) { this.showCount = showCount; } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值