filter用于筛选数据并改变流内容,peek仅观察数据且不改变流;filter保留满足条件的元素,peek对每个元素执行动作但不影响流结构,二者不可混用。

filter 是用来筛选数据的,peek 是用来观察数据的——两者目的不同,用错就容易白忙活。
filter 会改变流的内容
filter 接收一个 Predicate,只保留满足条件的元素,流的大小和内容都可能变化。它不是为了看数据,而是为了留下想要的数据。
- 执行后流中只剩符合条件的元素,后续操作只能基于这些结果
- 比如
stream.filter(n -> n > 3)后,4,5,6留下,1,2,3被丢弃 - 它是有业务语义的操作,常用于逻辑分支、权限校验、数据清洗等场景
peek 只做“路过式”查看
peek 接收一个 Consumer,对每个元素执行动作(如打印、计数、打日志),但不改变元素本身,也不影响流的结构或大小。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 必须搭配终止操作(如 collect、forEach)才会真正执行;单独写 peek 没输出
- 适合插在 filter 或 map 后面,确认“这一步到底留下了什么”或“转换成什么样了”
- 例如:
.filter(n -> n > 3).peek(System.out::println).map(n -> n * 2),能清楚看到过滤后的原始值,再进入映射
调试时混用 peek 和 filter 的典型误区
有人试图用 peek 替代 filter,比如写 .peek(n -> { if (n ,这完全无效——peek 不拦截、不过滤,只是“看了一眼就放行”。
- filter 是声明式裁剪,peek 是声明式观察,二者不可互换
- 把业务逻辑塞进 peek(如修改外部集合、更新状态)违反函数式原则,且在并行流中行为不可靠
- 调试完成后应删掉 peek,生产环境留着不仅无益,还可能掩盖性能问题
组合使用更高效地定位问题
真实调试中,filter 和 peek 配合才能看清全链路:
- 在 filter 前 peek:确认原始输入是否符合预期
- 在 filter 后 peek:验证筛选逻辑是否写对(比如边界值、null 处理)
- 在 map 或 flatMap 后 peek:检查转换结果是否符合类型或格式要求
- 多个 peek 可串联,顺序反映处理流程,输出天然带上下文
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










