跟踪流

pit*_*las 9 java java-8 java-stream

我正在使用Java 8流,并想提出一种调试它们的方法.所以我想我可以编写一个过滤器,在流的一个阶段打印出元素,如下所示:

int[] nums = {3, -4, 8, 4, -2, 17, 9, -10, 14, 6, -12};
int sum = Arrays.stream(nums)
    .filter(w -> {System.out.print(" " + w); return true;}) // trace
    .map(n -> Math.abs(n))
    .filter(w -> {System.out.print(" " + w); return true;}) // trace
    .filter(n -> n % 2 == 0)
    .distinct()
    .sum();
System.out.println(sum);
Run Code Online (Sandbox Code Playgroud)

关闭,但这不是它,因为它没有适当的分隔符使其清晰:

 3 3 -4 4 8 8 4 4 -2 2 17 17 9 9 -10 10 14 14 6 6 -12 1256
Run Code Online (Sandbox Code Playgroud)

我想要的是:

[3, -4, 8, 4, -2, 17, 9, -10, 14, 6, -12]
[3 4 8 4 2 17 9 10 14 6 12]
56
Run Code Online (Sandbox Code Playgroud)

有更标准的方法吗?请注意Peek作为链接文章说没有这样做,因为我想以某种方式想要在每个阶段收集流的所有元素.

Pau*_*ton 9

您需要为每个检查点使用不同的列表.

通常我不建议使用流操作以这种方式改变状态,但出于调试目的,我认为没关系.事实上,正如@BrianGoetz在下面指出的那样,调试peek是添加的原因.

int[] nums = {3, -4, 8, 4, -2, 17, 9, -10, 14, 6, -12};
List<Integer> checkPoint1 = new ArrayList<>();
List<Integer> checkPoint2 = new ArrayList<>();
List<Integer> checkPoint3 = new ArrayList<>();
List<Integer> checkPoint4 = new ArrayList<>();
int sum = Arrays.stream(nums)
                .peek(checkPoint1::add)
                .map(n -> Math.abs(n))
                .peek(checkPoint2::add)
                .filter(n -> n % 2 == 0)
                .peek(checkPoint3::add)
                .distinct()
                .peek(checkPoint4::add)
                .sum();
System.out.println(checkPoint1);
System.out.println(checkPoint2);
System.out.println(checkPoint3);
System.out.println(checkPoint4);
System.out.println(sum);
Run Code Online (Sandbox Code Playgroud)

输出:

[3, -4, 8, 4, -2, 17, 9, -10, 14, 6, -12]
[3, 4, 8, 4, 2, 17, 9, 10, 14, 6, 12]
[4, 8, 4, 2, 10, 14, 6, 12]
[4, 8, 2, 10, 14, 6, 12]
56
Run Code Online (Sandbox Code Playgroud)

  • @PaulBoddington就像其他一切一样,操作融合是一种权衡.99 +%的时间,你喜欢它给你的表现; 一小部分时间,它阻碍了发现正在发生的事情,然后你打破一些(通常是狡猾或侵入性的)工具来检查发生了什么.(声明性查询语言总是这样; SQL实现需要工具来检查查询计划和表统计信息,以便我们可以看到当我们对查询编码错误时会发生什么.) (6认同)
  • 这正是我们添加`peek()`的原因。 (2认同)

the*_*472 6

如果您经常发现自己需要Paul的解决方案,那么可以编写一个静态包装函数来生成索引的peek函数:

int sum = streamDebugger<Integer>((Supplier<Consumer<?>> peekGen) => {
   return Arrays.stream(nums)
                .peek(peekGen.get())
                .map(n -> Math.abs(n))
                .peek(peekGen.get())
                .filter(n -> n % 2 == 0)
                .peek(peekGen.get())
                .distinct()
                .peek(peekGen.get())
                .sum();
})
Run Code Online (Sandbox Code Playgroud)

为了进一步自动化这一步,甚至可以包装整个流接口,以便每个定义的接口方法再次返回一个包装的实现,该实现自动对管道中的每个步骤进行窥视:

int sum = debugIntStream(Arrays.stream(nums))
                .map(n -> Math.abs(n))
                .filter(n -> n % 2 == 0)
                .distinct()
                .sum();
Run Code Online (Sandbox Code Playgroud)

由于实施相当繁琐,并且希望没有必要,因此实施留给读者.