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


系列文章导航:

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

相关推荐
excel8 小时前
Nuxt 中使用 useHead 优化 SEO 与 GEO
前端
落魄实习生8 小时前
Agent Scope Java 2.x 系列【10】Middleware
java·开发语言·ai
IT_陈寒9 小时前
SpringBoot启动慢得像蜗牛?原来是这个配置在捣鬼
前端·人工智能·后端
计算机魔术师9 小时前
Muse Spark跑赢Gemini,但真正的底牌是这种设计
前端
PYB39 小时前
【Web·JS·基础】函数的使用和展运算符...objs
前端·javascript
ZealSinger9 小时前
Spring7 RestTemplate弃用迁移
java·spring·后端开发·restclient
指针向南9 小时前
Chrome读不了HEIC怎么办:原生解码和WASM两条路
前端·图像处理·人工智能·chrome·计算机视觉·wasm
朝朝辞暮i10 小时前
C++ 第 13 课:值传递 —— 为什么函数里改了,外面却没变?
java·c++·算法
弹简特10 小时前
【Java项目-企悦抽】16-抽奖模块01-获取活动完整信息接口实现
java·开发语言·状态模式·springboot
默_笙10 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript