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 深入、以及数据统计的完整实战。


系列文章导航:

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

相关推荐
OxYGC6 分钟前
Spring 面经系列 · 第 6 篇:Spring MVC 请求全流程、父子容器与零配置原理
java·spring·mvc
code2cat9 分钟前
Java高级篇之JDBC:连接数据库,完成查询、更新与事务
java·开发语言·数据库
bksczm15 分钟前
Redis数据结构之string
java·redis·mybatis
এ慕ོ冬℘゜16 分钟前
ES Promise.all/ Promise.race
前端·javascript·elasticsearch
cc_瀚海知行17 分钟前
资料检索 1|直接放入全文、按需读文件和先检索,有什么区别?
java·人工智能·ai
BioRunYiXue37 分钟前
使用docker分析高通量测序数据
java·数据库·人工智能·spring cloud·docker·tomcat·html
Shaoshing1 小时前
缓存一致问题及常见解决方案
java·缓存
喜欢打篮球的普通人1 小时前
LLVM 前端与优化层:Clang 如何把 C 代码变成 IR
c语言·前端·状态模式
聚美智数1 小时前
文档转换 API‑文档转 PDF‑PDF 转文档‑异步文档处理‑文件格式迁移‑转换结果回调推送 API 接口介绍
android·java·pdf
大文说跨境1 小时前
亚马逊多店铺用过多款指纹浏览器,说点长期用的实际感受
前端·网络