我试图理解如何调用非终端流操作.

Stream.of("aaa", "bbb", "ccc")
        .map(s -> {
            System.out.println(s);
            return s.toUpperCase();
        });
//prints nothing

Stream.of("aaa", "bbb", "ccc")
        .map(s -> {
            System.out.println(s);
            return s.toUpperCase();
        })
        .forEach(s -> {});
//prints "aaa" "bbb" "ccc"

这对我来说似乎很清楚.

第一个流没有以终端操作结束,因此它不会调用非终端操作,也不会打印任何内容.

Stream.of("aaa", "bbb", "ccc")
        .map(s -> {
            System.out.println(s);
            return s.toUpperCase();
        })
        .findFirst();
//prints "aaa"

Stream.of("aaa", "bbb", "ccc")
        .map(s -> {
            System.out.println(s);
            return s.toUpperCase();
        })
        .filter(s -> s.startsWith("B"))
        .findFirst();
//prints "aaa" "bbb"

这就是我感到困惑的地方,尤其是最后一个.从某种意义上看,这条流是"向后"运行的.首先判断终端操作返回的元素,然后只对这些元素执行中间操作.但是如何解释最后一个呢?看起来它对所有元素进行了映射,直到与过滤器匹配的第一个元素.在最后一个例子中,如果我用forEach()替换findFirst(),它会打印所有元素,即使最后只有一个元素.

对我来说似乎有点违反直觉.谁能给我一个恰当的解释,流如何识别它应该执行中间操作的元素?

推荐答案

第一个流没有以终端操作结束,因此它不会调用非终端操作,也不会打印任何内容.

Terminal operation-生成并返回流执行结果的操作,或作为副作用执行最终操作(在forEach的情况下).另一方面,intermediate operation是始终返回另一个流的流操作,它意味着以某种方式转换流管道.

当一个流幸运地达到terminal operation时,它将被执行not.这允许您在一个方法中创建一个流,并将其分发给另一个方法,在该方法中,它将附加一些额外的操作(包括终端)并得到执行.

首先判断终端操作返回的元素,然后只对这些元素执行中间操作.

不,它不是那样工作的.

流是lazy,这意味着每个动作只在需要时发生.流doesn't就像由for个循环组成的链.

例如,如果我们有一个filter操作,后跟一个map操作,只有当元素通过filter时,才会应用map,这意味着流源中的一个元素进入filter,如果它通过filter,它将被分发给map,然后进入terminal operation,如果流没有终止,源中的另一个元素重复相同的步骤.

在您的示例中,Stream.of().map().filter().findFirst()个流元素将从源中一个接一个地出现,直到没有找到第一个通过filter的流元素.当一个元素通过filter时,流终止,findFirst返回该元素.

在大多数情况下,一次只处理一个流元素,只有sorting()个流元素需要将所有流数据转储到内存中进行排序.

以下是Stream API documentation人的一句话:

Intermediate operations返回新流.他们总是lazy

...

惰性处理流可以显著提高效率;在一个

有些操作独立于其他元素处理每个元素,它们不保留有关以前遇到的元素的信息,称为stateless(例如:filtermapflatMap等).另一方面,一些操作(如distincttakeWhilesorted等)需要关于先前处理的元素的信息来执行与下一个元素的操作,即它们需要保持状态,因此称为stateful.

另外,请看与流处理相关的this question个.

Java相关问答推荐

如何从片段请求数据到活动?在主要活动中单击按钮请求数据?

当列顺序更改时,Table View列列表的Change. wasPermanted()总是返回假

Saxon 9:如何从Java扩展函数中的net.sf.saxon.expr. XPathContent中获取声明的变量

Java取消任务运行Oracle查询通过JDBC—连接中断,因为SQLSTATE(08006),错误代码(17002)IO错误:套接字读取中断

Javascript在边界中心调整ImageView大小

Jlink选项&-strie-ative-Commands";的作用是什么?

使用Testcontainers与OpenLiberty Server进行集成测试会抛出SocketException

Spark忽略Iceberg Nessie目录

PDFBox未加载内容

我怎样才能让IntelliJ标记toString()的任何实现?

SpringBoot:在条件{Variable}.isBlank/{Variable}.isEmpty不起作用的情况下进行路径变量验证

与IntArray相比,ArrayList<;Int>;对于大量元素的性能极差

JavaFX:无论何时显示应用程序,如何更改组件/ node 位置?

Java.time.OffsetDateTime的SQL Server数据库列类型是什么?

如何使用WebEnvironment.RANDOM_PORT获得第二个随机端口?

Android无法在Java代码中调用Kotlin代码,原因是在Companion中使用Kotlin枚举时

如何在Selenium上继续使用最新的WebDriver版本

如何使用Jackson读取以方括号开头的JSON?

在外部类和内部类之间,当调用外部类内部或外部的主方法时,它们的静态初始化程序的运行顺序不同

如何在 Android Studio 中删除 ImageView 和屏幕/父级边缘之间的额外空间?