Stream 实战:博客列表排序、过滤与分页(AI 辅助学习 Java 8)

前两周学了 Lambda、函数式接口和 Stream 基础。今天在一个完整的博客接口场景中,用 Stream 实现排序、过滤、分页、统计功能。


一、通用分页:排序 + skip + limit

分页是后端最常见的功能。用 Stream 实现只需要三行:

java 复制代码
public List<Blog> getBlogsByPage(int page, int pageSize) {
    return blogs.stream()
            .sorted(Comparator.comparing(Blog::getCreateTime).reversed()) // 最新在前
            .skip((long) (page - 1) * pageSize)   // 跳过前面的数据
            .limit(pageSize)                       // 取一页
            .collect(Collectors.toList());
}

核心公式skip((page - 1) * pageSize)

页码 pageSize skip limit
第1页 10 0 10
第2页 10 10 10
第3页 10 20 10

二、带条件的分页:先过滤再分页

实际场景中,分页往往带有筛选条件:

java 复制代码
// 只看已发布的文章,按阅读量降序分页
public List<Blog> getPublishedByPage(int page, int pageSize) {
    return blogs.stream()
            .filter(Blog::isPublished)
            .sorted(Comparator.comparingInt(Blog::getViews).reversed())
            .skip((long) (page - 1) * pageSize)
            .limit(pageSize)
            .collect(Collectors.toList());
}

三、搜索 + 分页

关键词搜索后分页返回:

java 复制代码
public List<Blog> searchAndPaginate(String keyword, int page, int pageSize) {
    return blogs.stream()
            .filter(b -> b.getTitle().toLowerCase().contains(keyword.toLowerCase())
                    || b.getAuthor().contains(keyword))
            .skip((long) (page - 1) * pageSize)
            .limit(pageSize)
            .collect(Collectors.toList());
}

// 同时获取总数
long total = blogs.stream()
        .filter(b -> b.getTitle().toLowerCase().contains(keyword.toLowerCase()))
        .count();

四、统计面板:分组 + 聚合

按作者统计文章数和总阅读量

java 复制代码
Map<String, AuthorStats> stats = blogs.stream()
        .collect(Collectors.groupingBy(
                Blog::getAuthor,
                Collectors.collectingAndThen(
                        Collectors.toList(),
                        list -> new AuthorStats(
                                list.size(),
                                list.stream().mapToInt(Blog::getViews).sum()
                        )
                )
        ));

输出:

makefile 复制代码
张三: 3 篇, 总阅读 530
李四: 2 篇, 总阅读 750
王五: 2 篇, 总阅读 750

按标签统计文章数

java 复制代码
blogs.stream()
        .flatMap(b -> b.getTags().stream())  // 展平所有标签
        .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()))
        .entrySet().stream()
        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
        .forEach(entry -> System.out.println("  " + entry.getKey() + ": " + entry.getValue() + " 篇"));

输出:

makefile 复制代码
Java: 4 篇
前端: 2 篇
Optional: 1 篇
Docker: 1 篇
...

五、数据校验:allMatch / anyMatch

用 Stream 做数据校验也很方便:

java 复制代码
// 所有文章都有标题吗?
boolean allHaveTitle = blogs.stream()
        .allMatch(b -> b.getTitle() != null && !b.getTitle().isEmpty());

// 有没有作者名为空的?
boolean hasEmptyAuthor = blogs.stream()
        .anyMatch(b -> b.getAuthor() == null || b.getAuthor().isEmpty());

六、运行结果

本项目 StreamPaginationDemo.java 完整运行结果:

csharp 复制代码
=== 1. 分页查询 ===
  第 1 页 (每页3条):
    [2026-06-12T12:00] Java 8 Optional 最佳实践
    [2026-06-11T08:00] Docker 入门指南
    [2026-06-09T11:00] React Hooks 教程
  第 2 页:
    [2026-06-07T16:00] Java Stream API 详解
    [2026-06-05T09:00] Vue3 组合式 API
    [2026-06-03T14:00] Spring Boot 实战

=== 2. 带条件分页 ===
  已发布-第1页-按阅读量降序:
    [500阅读] Vue3 组合式 API
    [400阅读] React Hooks 教程

=== 3. 搜索 + 分页 ===
  搜索 'Java' 第1页:
    Java 8 Lambda 入门 (张三)
    Java Stream API 详解 (张三)
    Java 8 Optional 最佳实践 (张三)
  共 3 条结果

=== 4. 统计面板 ===
  张三: 3 篇, 总阅读 530
  李四: 2 篇, 总阅读 750
  王五: 2 篇, 总阅读 750
  各标签文章数:
    Java: 4 篇
    前端: 2 篇

=== 5. 数据校验 ===
  所有文章都有标题: true
  有空作者名: false

七、本周学习总结

第三周我们学习了 Stream API,完整路线:

python 复制代码
周二:Stream API 入门------创建、中间操作、终端操作
周四:filter/map/sorted------三个最常用的操作
周六:分页+搜索+统计------博客接口实战(本篇)

核心收获

知识点 关键方法 一句话
创建 Stream stream() / of() / generate() 数据源 → 流
过滤 filter(Predicate) 只要匹配的
转换 map(Function) 一对一转换
扁平化 flatMap 一对多再展平
排序 sorted(Comparator) 按规则排序
分页 skip(n) + limit(n) 跳过 + 取
统计 count() / sum() / average() 聚合计算
匹配 anyMatch / allMatch / noneMatch 是否有匹配

八、下周预告

第四周进入 Stream 进阶:Collectors 全家桶(toList/joining/groupingBy/partitioningBy)、flatMap 深入、以及数据统计的完整实战。


系列文章导航

更多请关注我的微信公众号,感谢!

相关推荐
圆山猫4 小时前
[Virtualization](四):Linux KVM/RISC-V 的 vCPU 运行路径
java·linux·risc-v
城管不管4 小时前
ReAct、Plan-and-Execute、Reflection 三大智能 Agent 范式核心区别
java·人工智能·算法·spring·ai·动态规划
郭老二4 小时前
【前端】vue3:编译步骤
前端
IT小白杨5 小时前
从环境制备到自动化工作流:多账号运营的工程化架构拆解
java·经验分享·自动化·安全架构·指纹浏览器
豆瓣鸡5 小时前
算法日记 - Day3
java·开发语言·算法
萧瑟余晖5 小时前
Java深入解析篇九之NIO详解
java·网络·nio
不在逃避q5 小时前
Trae/Vs Code/Cursor命令行无法跑npm命令
前端·arcgis·npm
mldong5 小时前
从 mldong 到 jeeflow:一个工作流引擎的独立进化
后端
夏殇之殁6 小时前
包中创建自定义列表项。 . 使用自定义列表项进行数据绑定 . 将天气预报数据保存到本地内存表,通过LiveBindings进行显示。 ...
服务器·前端·javascript
The Chosen One9856 小时前
高进度算法模板速记(待完善)
java·前端·算法