首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 泛型分頁工具方法:通用 List 分頁實作與使用範例

     編輯:Java 綜合教學

需求場景

Controller 接收前端分頁參數 (page, pageSize),Service 查詢返回完整 List<T>,需在記憶體中截取指定頁面資料返回。因應不同業務實體類型 (User, Order, Product...),需編寫通用泛型方法。

通用泛型分頁方法

/**
 * 通用列表分頁
 * @param list  完整資料列表
 * @param pageSize  每頁筆數
 * @param pageNo    頁碼 (從 1 開始)
 * @param        元素型別
 * @return          指定頁面的子列表
 */
public static  List getPage(List list, int pageSize, int pageNo) {
    // 參數防禦
    if (list == null || list.isEmpty() || pageSize <= 0 || pageNo <= 0) {
        return Collections.emptyList();
    }
    
    int total = list.size();
    int totalPages = (total + pageSize - 1) / pageSize; // 天花板除法
    
    // 頁碼超出範圍返回空列表 (或拋出異常視業務而定)
    if (pageNo > totalPages) {
        return Collections.emptyList();
    }
    
    // 計算起始/結束索引 (0-based)
    int fromIndex = (pageNo - 1) * pageSize;
    int toIndex = Math.min(fromIndex + pageSize, total);
    
    // 使用 subList 獲取視圖 (O(1),無複製開銷),再轉為新 ArrayList 斷開關聯
    return new ArrayList<>(list.subList(fromIndex, toIndex));
}

關鍵設計決策解析

決策點選擇理由
泛型宣告<T> List<T> getPage(List<T> ...)型別安全,編譯期檢查,呼叫端無需轉型
參數順序(list, pageSize, pageNo)資料源優先,配置參數在後
頁碼基準1-based (pageNo=1 為第一頁)符合人類直覺與前端慣例
邊界處理參數非法/超頁返回空列表避免 NPE/IndexOutOfBounds,語義清晰
實作方式list.subList() + new ArrayList()subList 是視圖零複製,新 ArrayList 斷開底層關聯避免副作用
回傳型別List<T> (非具體 ArrayList)面向介面編程,保留實作彈性

使用範例

// Service 層
public List getUsersPage(int pageNo, int pageSize) {
    List allUsers = userDao.findAll(); // 查詢全量 (注意:大資料量慎用!)
    List pageUsers = PageUtils.getPage(allUsers, pageSize, pageNo);
    return pageUsers.stream().map(this::convertToVO).collect(Collectors.toList());
}

// Controller 層
@GetMapping("/users")
public ResponseEntity> getUsers(
        @RequestParam(defaultValue = "1") int page,
        @RequestParam(defaultValue = "10") int size) {
    List data = userService.getUsersPage(page, size);
    long total = userDao.count(); // 總筆數單獨查詢
    return ResponseEntity.ok(new PageResult<>(data, total, page, size));
}

⚠️ 關鍵效能警示:記憶體分頁 vs 資料庫分頁

記憶體分頁 (本方法) 僅適用於:
  • 資料量小 ( < 10,000 筆)
  • 下拉選單、字典表、配置資料等全量快取場景
  • 原始查詢已經是小結果集 (如已按用戶 ID 過濾)
嚴禁用於:
  • 大表全量查詢再分頁 → OOM 風險、資料庫壓力大、網路傳輸浪費
  • 高併發介面
正確做法:資料庫分頁
// MySQL
SELECT * FROM user LIMIT ?, ?;  -- offset, pageSize

// PostgreSQL
SELECT * FROM user LIMIT ? OFFSET ?;

// SQL Server (2012+)
SELECT * FROM user ORDER BY id OFFSET ? ROWS FETCH NEXT ? ROWS ONLY;

// Oracle (12c+)
SELECT * FROM user OFFSET ? ROWS FETCH NEXT ? ROWS ONLY;

進階擴充:分頁結果封裝類

@Data
@AllArgsConstructor
public class PageResult {
    private List data;       // 當頁資料
    private long total;         // 總筆數
    private int pageNo;         // 當前頁碼
    private int pageSize;       // 每頁大小
    private int totalPages;     // 總頁數
    
    // 便利建構子
    public PageResult(List data, long total, int pageNo, int pageSize) {
        this.data = data;
        this.total = total;
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalPages = (int) Math.ceil((double) total / pageSize);
    }
    
    // 判斷是否有下一頁
    public boolean hasNext() { return pageNo < totalPages; }
    public boolean hasPrevious() { return pageNo > 1; }
}

Spring Data JPA 整合 (自動分頁)

public interface UserRepository extends JpaRepository {
    // 自動支援分頁
    Page findByActiveTrue(Pageable pageable);
}

// Service 使用
Page page = userRepository.findByActiveTrue(PageRequest.of(pageNo - 1, pageSize));
List content = page.getContent();
long total = page.getTotalElements();
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved