具有无序终端操作的 Stream.skip 行为
我已经阅读了这个和这个问题,但仍然怀疑观察到的行为是否是JDK作者的意图。Stream.skip
让我们有一个简单的数字1..20输入:
List<Integer> input = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
现在,让我们创建一个并行流,以不同的方式组合 with 并收集结果: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
使用任何其他无序终端操作(如 、 、 等)可以实现相同的结果。在这种情况下,删除步骤不会更改任何内容。似乎虽然 step 正确地使流从当前操作开始无序,但无序终端操作使整个流从最开始无序,尽管这可能会影响使用的结果。这对我来说似乎完全具有误导性:我希望使用无序收集器与在终端操作之前将流转换为无序模式并使用等效的有序收集器相同。forEach
findAny
anyMatch
unordered()
unordered()
skip()
所以我的问题是:
- 此行为是有意为之,还是 Bug?
- 如果是,它是否记录在某个地方?我读过 Stream.skip() 文档:它没有说任何关于无序终端操作的内容。此外,特征。未排序的文档不是很理解,并没有说整个流的排序将丢失。最后,包摘要中的“排序”部分也不涵盖这种情况。可能我错过了什么?
- 如果无序终端操作的目的是使整个流无序,为什么 step 只从这一点起就使它无序呢?我可以依赖此行为吗?或者我只是很幸运,我的第一个测试工作得很好?
unordered()