我正在使用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作为链接文章说不会这样做,因为我想要在每个阶段收集流的所有元素。
答案 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();
由于实施起来相当繁琐,并且希望没有必要,因此可以由读者实施。