英文:
Java 8 Streams peek/map without collecting is not giving output
问题
以下是要翻译的内容:
"The below code is not printing any values. None of the System.out.println() statements are getting printed. I assumed peek deals with modifying data. Surprisingly the logic inside the peek() is not even getting executed.
If I collect the stream using Collectors I see the desired behavior.
- Why at least the print statement 1 isn't getting executed?
- Why isn't the external object (output list) is not getting appended with the desired values?"
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
List<String> input = new ArrayList<>(Arrays.asList("hello", "bye", "vacation"));
List<String> output = new ArrayList<>();
input.stream().peek(x -> {
System.out.println(x+"inside"); // print statement 1
if (x.length() > 3) {
output.add(x.toUpperCase());
}
});
output.forEach(System.out::println); // print statement 2
}
}
英文:
The below code is not printing any values. None of the System.out.println() statements are getting printed. I assumed peek deals with modifying data. Surprisingly the logic inside the peek() is not even getting executed.
If I collect the stream using Collectors I see the desired behavior.
- Why at least the print statement 1 isn't getting executed?
- Why isn't the external object (output list) is not getting appended with the desired values?
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
List<String> input = new ArrayList<>(Arrays.asList("hello", "bye", "vacation"));
List<String> output = new ArrayList<>();
input.stream().peek(x -> {
System.out.println(x+"inside"); // print statement 1
if (x.length() > 3) {
output.add(x.toUpperCase());
}
});
output.forEach(System.out::println); // print statement 2
}
}
答案1
得分: 3
代码中存在一些问题:
- Stream没有使用终端操作关闭,因此没有调用任何流操作。
Stream::peek
是主要用于调试的中间操作。- 在流中永远不应该使用任何有副作用或状态的操作 - 调用
output.add(x.toUpperCase());
不是一个好的做法。 output
为空,因此只有在关闭Stream时(参见第1点)才会打印出内容。
您只需要理解Stream API的内容,可以总结如下:
List<String> output = input.stream() // Stream<String>
.peek(x -> System.out.println(x + " inside")) // 打印每个值
.filter(x -> x.length() > 3) // 过滤长度大于3的字符串
.map(x -> x.toUpperCase()) // 使用map将它们转换为大写
.collect(Collectors.toList()); // 转换为List - 终端操作
英文:
There are several issues in the code:
- The Stream is not closed with a terminal operation, therefore no pipeline operation is invoked.
Stream::peek
is an intermediate operation used mainly for debugging.- You should never use any side-effect or stateful operation inside the stream - calling
output.add(x.toUpperCase());
is not good. - The
output
is empty so nothing is printed out as long as the Stream is not closed (see the no. 1).
All you need to understand Stream API is at the package description. Finally, you can conclude into something like:
List<String> output = input.stream() // Stream<String>
.peek(x -> System.out.println(x + " inside")) // print each value
.filter(x -> x.length() > 3) // filter Strings longer than 3 chars
.map(x -> x.toUpperCase()) // make them uppercase using map
.collect(Collectors.toList()); // to List - a terminal operation
答案2
得分: 2
当引用Stream#peek(Consumer)
时,会从现有的Stream
创建一个新的StatelessOp
对象。然而,仅当消耗Stream元素时才会调用StatelessOp
对象中的opWrapSink
方法。您在任何时候都没有消耗Stream的元素。在文档中的理由是中间操作是懒惰执行的。
寻求懒惰性。许多流操作,如过滤、映射或去重,可以以惰性方式实现,从而提供了优化的机会。例如,"查找具有三个连续元音字母的第一个字符串"不需要检查所有输入字符串。流操作分为中间操作(生成流)和终端操作(生成值或副作用)。中间操作始终是惰性的。
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
英文:
When Stream#peek(Consumer)
is referenced, a new StatelessOp
object is created from the existing Stream
. However, the method from the StatelessOp
object called opWrapSink
is only called when the Stream elements are consumed. You are not consuming the elements of the Stream at any point. In the documentation the reasoning is that intermediate operations are done lazily.
> Laziness-seeking. Many stream operations, such as filtering, mapping,
> or duplicate removal, can be implemented lazily, exposing
> opportunities for optimization. For example, "find the first String
> with three consecutive vowels" need not examine all the input strings.
> Stream operations are divided into intermediate (Stream-producing)
> operations and terminal (value- or side-effect-producing) operations.
> Intermediate operations are always lazy.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
答案3
得分: 0
你的流缺少终端操作符,所以它不会执行任何操作。
请参阅 https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html:
> 中间操作返回一个新的流。它们始终是延迟执行的;执行中间操作,如 filter(),实际上并不执行任何过滤操作,而是创建一个新的流,当遍历时,它包含与给定谓词匹配的初始流的元素。只有在管道的终端操作被执行之后,才会开始遍历管道源。
.collect
是一个终端操作符,这就解释了为什么当你用 collect
替换 close
时它起作用。
英文:
You lack a terminal operator on your stream, so nothing will happen with it.
See https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html:
> Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.
The .collect
is a terminal operator which explains why it works when you replace close
with collect
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论