发布于2026-07-15 阅读(0)
扫一扫,手机访问
要说调试 Stream 流程最轻量的方式,非 peek 莫属。它扮演的是一个“中间观察员”的角色——每个元素流过时,你可以让它执行某个动作(比如打印一行日志),但它本身不会改动数据。简单说,就是让你在过滤、映射这些中间步骤之间“偷看一眼”当前的状态。

其实核心就一句话:Stream.peek() 不改变数据,只在每个元素经过时执行你指定的操作,比如打印日志。 但要记住,它是个中间操作,必须后面跟上终止操作才会真正干活,否则你写再多 peek 都是白搭。
熟悉 Stream 的都知道,它是惰性求值的——filter、map 这些中间操作不会立即执行,只有遇到 collect、forEach 这类终止操作时,整条流水线才会动起来。而 peek 就是在链条上“插个眼”,让你看到某个环节的元素长什么样。
注意一个关键点:peek 必须放在终止操作之前,否则什么都不会打印。这不是 bug,是设计。
直接传一个 Lambda 表达式进去,用 System.out.println 输出就行。
Listlist = Arrays.asList("apple", "banana", "cherry"); list.stream() .filter(s -> s.length() > 5) .peek(s -> System.out.println("过滤后拿到:" + s)) .map(String::toUpperCase) .peek(s -> System.out.println("转大写后:" + s)) .collect(Collectors.toList());
输出结果一目了然:
过滤后拿到:banana 转大写后:BANANA 过滤后拿到:cherry 转大写后:CHERRY
AtomicInteger 或 IntStream.range,精准定位第几个元素出了问题。peek 的 Lambda 里加一行 Debugger.breakpoint()(Ja va 14+),或者直接在 IDE 的行号上打断点(部分 IDE 支持 Lambda 内的断点)。.peek(s -> { if (s.contains("err")) System.out.println("可疑项:" + s); })。s += "!"),更不该用来做业务逻辑(比如调用 service.sa ve())。它的本职工作只是看一看。forEach 是终止操作,一执行完流就结束了;peek 是中间操作,必须后面还有终止操作才能生效。下面这段代码什么都不会打印:
list.stream().peek(System.out::println); // ❌ 没有终止操作,整条流根本没运行
而这样才行:
list.stream().peek(System.out::println).count(); // ✅ count 是终止操作
peek 里的 println 仍然会执行——应改用 SLF4J 等支持日志级别的方案,避免意外输出。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8