Java:流中的消费者界面未按预期工作
Java: Consumer interface in a stream doesn't work as expected
我有 2 个陈述,我希望它们 "print" 相同的结果:
Arrays.stream("abc".split("")).forEach(System.out::println);//first
Arrays.stream("abc".split("")).peek(new Consumer<String>() {//second
@Override
public void accept(String s) {
System.out.println(s);//breakpoint
}
});
其实第一条语句会打印
a
b
c
好的,但是第二个语句没有打印任何内容。我尝试在 IntelliJ 中的“//breakpoint”行设置断点,但没有被击中。
那么我应该如何更改第二个语句以使用 "peek" 因为它在使用 "Consumer" 处理每个元素时创建一个新流?
非常感谢。
peek()
不是终端操作,它产生中间流。您的流只有在 发现 终端操作时才会执行。
例如:如果您将 count()
终端操作添加到您的第二个流,您将获得预期的输出。
注意 - 您得到了第一个流的输出,因为 forEach()
是一个终端操作。
peek()
不是终端操作,您需要添加任何终端操作才能使 peek 工作,例如
Arrays.stream("abc".split("")).peek(new Consumer<String>() { //second
@Override
public void accept(String s) {
System.out.println(s);//breakpoint
}
}).count();
流操作分为中间(Stream-producing)
操作和终端(value- or side-effect-producing)
操作。中间操作总是 lazy
。因此,一旦获得任何终端操作,Steam 就会开始执行操作管道。在您的第一种情况下 forEach
是终端操作,因此执行了流。但在第二种情况下,管道中的最后一个操作是 peek()
,这不是终端操作。
Stream.peek
,正如 API 的 javadoc 中所述,主要用于调试目的,不建议在 peek 操作期间对流执行任何更新操作。
例如,您可以使用以下代码验证中间流状态及其最终结果:
Arrays.stream("acb".split(""))
.peek(System.out::println) // print a c b
.sorted()
.forEach(System.out::println); // print a b c
一般来说,这个操作是一个中间操作不会被执行,除非终端操作如前所述在流上执行在文档的 Stream operations and pipelines 部分,这正是您的 第一条语句将打印 .
的原因
注意:尽管如其他一些答案中所建议的那样,peek
中的操作
在能够优化某些短路操作(如 findFirst
等
的结果的情况下不会被调用
In cases where the stream implementation is able to optimize away the
production of some or all the elements (such as with short-circuiting
operations like findFirst
, or in the example described in count()
),
the action will not be invoked for those elements.
我有 2 个陈述,我希望它们 "print" 相同的结果:
Arrays.stream("abc".split("")).forEach(System.out::println);//first
Arrays.stream("abc".split("")).peek(new Consumer<String>() {//second
@Override
public void accept(String s) {
System.out.println(s);//breakpoint
}
});
其实第一条语句会打印
a
b
c
好的,但是第二个语句没有打印任何内容。我尝试在 IntelliJ 中的“//breakpoint”行设置断点,但没有被击中。
那么我应该如何更改第二个语句以使用 "peek" 因为它在使用 "Consumer" 处理每个元素时创建一个新流?
非常感谢。
peek()
不是终端操作,它产生中间流。您的流只有在 发现 终端操作时才会执行。
例如:如果您将 count()
终端操作添加到您的第二个流,您将获得预期的输出。
注意 - 您得到了第一个流的输出,因为 forEach()
是一个终端操作。
peek()
不是终端操作,您需要添加任何终端操作才能使 peek 工作,例如
Arrays.stream("abc".split("")).peek(new Consumer<String>() { //second
@Override
public void accept(String s) {
System.out.println(s);//breakpoint
}
}).count();
流操作分为中间(Stream-producing)
操作和终端(value- or side-effect-producing)
操作。中间操作总是 lazy
。因此,一旦获得任何终端操作,Steam 就会开始执行操作管道。在您的第一种情况下 forEach
是终端操作,因此执行了流。但在第二种情况下,管道中的最后一个操作是 peek()
,这不是终端操作。
Stream.peek
,正如 API 的 javadoc 中所述,主要用于调试目的,不建议在 peek 操作期间对流执行任何更新操作。
例如,您可以使用以下代码验证中间流状态及其最终结果:
Arrays.stream("acb".split(""))
.peek(System.out::println) // print a c b
.sorted()
.forEach(System.out::println); // print a b c
一般来说,这个操作是一个中间操作不会被执行,除非终端操作如前所述在流上执行在文档的 Stream operations and pipelines 部分,这正是您的 第一条语句将打印 .
的原因注意:尽管如其他一些答案中所建议的那样,peek
中的操作
在能够优化某些短路操作(如 findFirst
等
In cases where the stream implementation is able to optimize away the production of some or all the elements (such as with short-circuiting operations like
findFirst
, or in the example described incount()
), the action will not be invoked for those elements.