Stream.limit()和skip()可组合实现内存分页,即skip((pageNum-1)*pageSize).limit(pageSize),适用于已加载内存的中小数据集,不适用于数据库等外部数据源物理分页。

Java 中的 Stream.limit() 和 Stream.skip() 可以组合实现轻量级内存分页(即对已加载到内存的集合做逻辑分页),但需注意:它们不适用于数据库或大文件等外部数据源的物理分页,仅适合中小规模、已全部在内存中的数据集合。
分页逻辑与典型用法
分页本质是“跳过前 N 条,再取 M 条”。对应 Stream 操作即:skip(pageSize * (pageNum - 1)).limit(pageSize)。其中 pageNum 从 1 开始,pageSize 为每页条数。
- 第 1 页(pageNum=1):skip(0).limit(10) → 取索引 0~9
- 第 2 页(pageNum=2):skip(10).limit(10) → 取索引 10~19
- 第 3 页(pageNum=3):skip(20).limit(10) → 取索引 20~29
基础实现示例(List 分页)
对 List<string></string> 进行内存分页:
List<String> data = Arrays.asList("a", "b", "c", "d", "e", "f", "g");
int pageNum = 2;
int pageSize = 3;
<p>List<String> page = data.stream()
.skip((long) (pageNum - 1) * pageSize)
.limit(pageSize)
.collect(Collectors.toList());</p><p>System.out.println(page); // [d, e, f]
⚠️ 注意:skip() 参数类型为 long,大页码时需强转避免整型溢出;limit() 后流终止,无法复用。
立即学习“Java免费学习笔记(深入)”;
安全分页:避免越界与空指针
原始集合可能小于总页数,直接 skip 超出范围不会报错,但会返回空结果。建议封装为健壮方法:
public static <T> List<T> paginate(List<T> list, int pageNum, int pageSize) {
if (list == null || pageNum < 1 || pageSize < 1) return Collections.emptyList();
<pre class="brush:php;toolbar:false;">long skipCount = (long) (pageNum - 1) * pageSize;
if (skipCount >= list.size()) return Collections.emptyList();
return list.stream()
.skip(skipCount)
.limit(pageSize)
.collect(Collectors.toList());}
该方法显式检查越界,避免无效 skip,并兼容空集合和非法参数。
数据截断:limit() 的独立用途
limit(n) 单独使用可实现“取前 N 条”场景,例如日志采样、Top-N 截断:
- 获取前 5 条用户记录:
users.stream().limit(5).toList() - 防止误处理全量数据:
process(stream.limit(1000))作为安全兜底 - 与 sorted() 组合取 Top-K:
stream.sorted(comparator).limit(k)
注意:limit 是短路操作,配合无限流(如 Stream.iterate)可生成有限序列;但对有序流慎用 skip+limit,因 skip 仍需遍历前序元素,性能随页码增大而下降。


















