以下是我的代码片段,结果总是显示:
main sort3
main sort3
main sort3
main sort3
peek
之后的sorted
似乎没有运行。你遇到过这种奇怪的事情吗?
public static void main(String[] args) throws InterruptedException {
Random random = new Random();
Stream<Integer> parallel = Stream.generate(() -> random.nextInt(1000))
.limit(10)
.sorted((a, b) -> {
System.out.println(Thread.currentThread().getName() + " sort3 ");
return a.compareTo(b);
}) //3
.peek(i -> System.out.println(Thread.currentThread().getName() + " peek4 " + i)) //4
.peek(i-> System.out.println(Thread.currentThread().getName()+" peek5 " + i)) //5
.parallel().count();
Thread.sleep(20000);
}
流上的
peek
方法不能保证被调用,即使存在元素也是如此。 特别是,当流能够优化临时操作时,例如在已知大小的流上调用 count
时,可能不会调用它。
在这种情况下,
sort
操作处理流的所有元素,并产生包含 10 个元素的流。 流实现能够确定最终计数操作的值为 10,而无需执行临时 peek
操作。 因此,它跳过 peek
调用作为优化。
在我的 Java 版本中,此方法的并行版本调用
peek
,但顺序版本则不会。 顺序版本的实现跳过调用 peek
或并行版本调用它也是正确的。 最终,是否在特定情况下调用peek
取决于实现。 因此,依靠 peek
来保证程序正确性通常是一个坏主意,而仅将其用于调试流管道的既定目的。
此类
peek
/count
场景在 peek
和 count
文档中都有描述。
peek
API说明:
此方法的存在主要是为了支持调试,您希望在元素流过管道中的某个点时查看元素:
[…]
在流实现能够优化部分或全部元素的生产的情况下(例如使用像
这样的短路操作,或者在findFirst
中描述的示例),该操作将不会为这些元素调用。count()
count
API说明:
如果实现能够直接从流源计算计数,则可以选择不执行流管道(顺序或并行)。在这种情况下,不会遍历任何源元素,也不会评估任何中间操作。具有副作用的行为参数可能会受到影响,除了调试等无害情况外,强烈建议不要这样做。例如,考虑以下流:
List<String> l = Arrays.asList("A", "B", "C", "D"); long count = l.stream().peek(System.out::println).count();
流源
覆盖的元素数量是已知的,并且中间操作List
不会向流中注入或删除元素(可能是peek
或flatMap
操作)。因此,计数是filter
的情况)的大小,无需执行管道,并且作为副作用,打印出列表元素。List