Java 利用peek方法对流进行调试

Java 利用peek方法对流进行调试,用户希望在处理流时查看流中的各个元素,根据需要,在流的流水线中调用 java.util.stream.Stream 接口定义的中间操作 peek。流处理由一系列零个或多个中间操作构成,后跟终止操作。每个中间操作都返回一个新的流,而终止操作将返回不是流的值。

Java 利用peek方法对流进行调试 问题描述

用户希望在处理流时查看流中的各个元素。

Java 利用peek方法对流进行调试 解决方案

根据需要,在流的流水线中调用 java.util.stream.Stream 接口定义的中间操作 peek

Java 利用peek方法对流进行调试 具体实例

流处理由一系列零个或多个中间操作构成,后跟终止操作。每个中间操作都返回一个新的流,而终止操作将返回不是流的值。
对于流的流水线所涉及的中间操作序列,初次接触 Java 8 的用户有时候会感到困惑,因为无法在处理流时查看各个元素的值。
我们考虑这样一个简单的方法,即接受某个整数流的开始范围和结束范围,并将每个数字倍增,然后仅对能被 3 整除的结果值求和,如例 3-32 所示。

例 3-32 对整数进行倍增、筛选与求和

public int sumDoublesDivisibleBy3(int start, int end) {
    return IntStream.rangeClosed(start, end)
        .map(n -> n * 2)
        .filter(n -> n % 3 == 0)
        .sum();
}

编写一个简单的测试,验证程序可以正确执行:

@Test
public void sumDoublesDivisibleBy3() throws Exception {
    assertEquals(1554, demo.sumDoublesDivisibleBy3(100, 120));
}

上述测试虽然有一定帮助,但并未提供太多有价值的信息。如果代码无法运行,很难找出症结所在。
如例 3-33 所示,我们为流水线添加一个 map 操作,传入并打印每个值,然后再次返回这些值。

例 3-33 添加标识映射以便打印

public int sumDoublesDivisibleBy3(int start, int end) {
    return IntStream.rangeClosed(start, end)
        .map(n -> { ➊
            System.out.println(n);
            return n;
        })
        .map(n -> n * 2)
        .filter(n -> n % 3 == 0)
        .sum();
}

➊ 标识映射(identity map)打印并返回每个元素
程序将打印从 start(含)到 end(含)的数字,每行一个数字。尽管不应在生产环境中使用上述代码,但它的确能让用户在不影响流处理的同时观察其内部操作。
这正是 Stream 接口中 peek 方法的工作原理,该方法的声明如下:

Stream<T> peek(Consumer<? super T> action)

根据 Javadoc 的描述,peek 方法“返回一个由流的元素构成的流,当元素从所生成的流中消耗时,对每个元素执行给定的操作”。由于 Consumer 仅传入一个输入而不返回任何值,所提供的 Consumer 不会对值造成破坏。
peek 方法是一种中间操作,可以根据需要多次添加,如例 3-34 所示。

例 3-34 使用多个 peek 方法

public int sumDoublesDivisibleBy3(int start, int end) {
    return IntStream.rangeClosed(start, end)
        .peek(n -> System.out.printf("original: %d%n", n)) ➊
        .map(n -> n * 2)
        .peek(n -> System.out.printf("doubled : %d%n", n)) ➋
        .filter(n -> n % 3 == 0)
        .peek(n -> System.out.printf("filtered: %d%n", n)) ➌
        .sum();
}

❶ 在倍增前打印值
❷ 在倍增后、筛选前打印值
❸ 在筛选后、求和前打印值
程序将显示每个元素的初始值、倍增值以及筛选后的值,输出结果如下:

original: 100
doubled : 200
original: 101
doubled : 202
original: 102
doubled : 204
filtered: 204
...
original: 119
doubled : 238
original: 120
doubled : 240
filtered: 240

略显不便的是,很难将用于测试的 peek 方法设置为可选。因此,尽管 peek 方法有助于调试,但不应将其置于生产环境中。

赞(2)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Java 实例