跟踪流

时间:2016-04-09 20:53:05

标签: 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);

关闭,但事实并非如此,因为它没有合适的分隔符来使其清晰可读:

 3 3 -4 4 8 8 4 4 -2 2 17 17 9 9 -10 10 14 14 6 6 -12 1256

我想要的是:

[3, -4, 8, 4, -2, 17, 9, -10, 14, 6, -12]
[3 4 8 4 2 17 9 10 14 6 12]
56

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

2 个答案:

答案 0 :(得分: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);

输出:

[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

答案 1 :(得分: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();
})

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

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

由于实施起来相当繁琐,并且希望没有必要,因此可以由读者实施。