我已经阅读了
this和
this的问题,但仍然怀疑Stream.skip的观察行为是否是JDK作者的意图。
让我们简单输入数字1..20:
List input = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
现在让我们创建一个并行流,以不同的方式组合unordered()和skip(),并收集结果:
System.out.println("skip-skip-unordered-toList: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.skip(1)
.unordered()
.collect(Collectors.toList()));
System.out.println("skip-unordered-skip-toList: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.unordered()
.skip(1)
.collect(Collectors.toList()));
System.out.println("unordered-skip-skip-toList: "
+ input.parallelStream().filter(x -> x > 0)
.unordered()
.skip(1)
.skip(1)
.collect(Collectors.toList()));
过滤步骤本质上没有什么,但增加了流引擎的更多困难:现在它不知道输出的确切大小,因此一些优化被关闭。我有以下结果:
skip-skip-unordered-toList: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// absent values: 1, 2
skip-unordered-skip-toList: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20]
// absent values: 1, 15
unordered-skip-skip-toList: [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20]
// absent values: 7, 18
结果是完全正常,一切正常工作。在第一种情况下,我要求跳过前两个元素,然后收集到列表没有特定的顺序。在第二种情况下,我要求跳过第一个元素,然后变成无序,并跳过一个元素(我不在乎哪一个)。在第三种情况下,我首先变成无序模式,然后跳过两个任意元素。
让我们跳过一个元素并收集到无序模式下的自定义集合。我们的自定义集合将是一个HashSet:
System.out.println("skip-toCollection: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.unordered()
.collect(Collectors.toCollection(HashSet::new)));
输出是令人满意的:
skip-toCollection: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
// 1 is skipped
所以一般来说,我期望只要流是有序的,skip()跳过第一个元素,否则跳过任意的。
但是让我们使用一个等效的无序终端操作collect(Collectors.toSet()):
System.out.println("skip-toSet: "
+ input.parallelStream().filter(x -> x > 0)
.skip(1)
.unordered()
.collect(Collectors.toSet()));
现在的输出是:
skip-toSet: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20]
// 13 is skipped
使用任何其他无序的终端操作(例如forEach,findAny,anyMatch等)可以实现相同的结果。在这种情况下删除无序()步骤什么也不改变。看来,虽然unordered()步骤正确地使流从当前操作开始无序,无序的终端操作使得整个流从非常开始开始无序,尽管如果使用skip(),这可能影响结果。这似乎完全误导我:我期望使用无序收集器是相同的将流转换为无序模式就在终端操作和使用等效有序收集器之前。
所以我的问题是:
>这是行为意图还是它是一个错误?
>如果是的,它记录在哪里?我已经阅读Stream.skip()文档:它不说任何关于无序的终端操作。另外Characteristics.UNORDERED文档不是很理解,并且不说整个流的顺序将丢失。最后,Ordering部分在包摘要也不包括这种情况。可能我错过了什么?
>如果意图无序的终端操作使整个流无序,为什么unordered()步骤使它无序,只是因为这一点?我可以依靠这种行为吗?或者我只是幸运,我的第一个测试工作很好?