有条件地将操作添加到 Java 8 流

2024-03-24

我想知道是否可以根据流外部设置的某种条件向流添加操作。例如,我想向流添加限制操作,如果我的limit变量不等于-1.

我的代码目前看起来像这样,但我还没有看到以这种方式使用流的其他示例,其中 Stream 对象被重新分配给应用于自身的中间操作的结果:

// Do some stream stuff
stream = stream.filter(e -> e.getTimestamp() < max);

// Limit the stream
if (limit != -1) {
   stream = stream.limit(limit);
}

// Collect stream to list
stream.collect(Collectors.toList());

如本文所述堆栈溢出帖子 https://stackoverflow.com/questions/21219667/stream-and-lazy-evaluation,直到调用终端操作后才会真正应用过滤器。由于我在调用终端操作之前重新分配流的值,因此上面的代码仍然是使用 Java 8 流的正确方法吗?


一系列链接的调用和一系列存储中间返回值的调用之间没有语义差异。因此,以下代码片段是等效的:

a = object.foo();
b = a.bar();
c = b.baz();

and

c = object.foo().bar().baz();

无论哪种情况,都会根据前一个调用的结果调用每个方法。但在后一种情况下,中间结果不会被存储,而是会在下次调用时丢失。对于流 API,中间结果must not在调用其下一个方法后使用,因此链接是使用流的自然方式,因为它本质上确保您不会在返回的引用上调用多个方法。

不过,只要遵守不多次使用返回引用的约定,存储对流的引用就没有错。通过像您的问题中那样使用它,即用下一次调用的结果覆盖变量,您还可以确保不会在返回的引用上调用多个方法,因此,这是一种正确的用法。当然,这仅适用于相同类型的中间结果,因此当您使用map or flatMap,获取不同引用类型的流时,无法覆盖局部变量。然后你必须小心不要再次使用旧的局部变量,但是,正如所说的,只要你在下次调用后不使用它,中间存储就没有问题。

有时,你have存储它,例如

try(Stream<String> stream = Files.lines(Paths.get("myFile.txt"))) {
    stream.filter(s -> !s.isEmpty()).forEach(System.out::println);
}

请注意,该代码等效于以下替代方案:

try(Stream<String> stream = Files.lines(Paths.get("myFile.txt")).filter(s->!s.isEmpty())) {
    stream.forEach(System.out::println);
}

and

try(Stream<String> srcStream = Files.lines(Paths.get("myFile.txt"))) {
    Stream<String> tmp = srcStream.filter(s -> !s.isEmpty());
    // must not be use variable srcStream here:
    tmp.forEach(System.out::println);
}

它们是等价的,因为forEach总是根据以下结果调用filter总是根据以下结果调用Files.lines最终的结果并不重要close()当关闭影响整个流管道时调用操作。


用一句话来说,你使用它的方式是正确的。


I even prefer这样做,而不是链接limit当你不想应用限制时的操作是表达你的意图的最干净的方式。还值得注意的是,建议的替代方案可能在很多情况下都有效,但它们是not语义上等价:

.limit(condition? aLimit: Long.MAX_VALUE)

假设您可以遇到的最大元素数是Long.MAX_VALUE但流可以有更多的元素,它们甚至可能是无限的。

.limit(condition? aLimit: list.size())

当流源为list,正在打破流的惰性求值。原则上,可变流源可以合法地任意更改,直到终端操作开始为止。结果将反映到目前为止所做的所有修改。当您添加中间操作并结合list.size(),即此时列表的实际大小,对该点和终端操作之间的集合应用的后续修改可能会将该值变得与预期的“实际上没有限制”语义具有不同的含义。

与之比较API 文档的“无干扰”部分 http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#NonInterference:

对于行为良好的流源,可以在终端操作开始之前修改源,并且这些修改将反映在所覆盖的元素中。例如,考虑以下代码:

List<String> l = new ArrayList(Arrays.asList("one", "two"));
Stream<String> sl = l.stream();
l.add("three");
String s = sl.collect(joining(" "));

首先创建一个由两个字符串组成的列表:“one”;和“二”。然后从该列表创建一个流。接下来通过添加第三个字符串“三”来修改列表。最后,流的元素被收集并连接在一起。由于列表在终端收集操作开始之前被修改,因此结果将是“一二三”的字符串。

当然,这是一种罕见的极端情况,通常情况下,程序员将制定整个流管道,而不修改其间的源集合。尽管如此,不同的语义仍然存在,当您一旦进入这样的极端情况时,它可能会变成一个很难发现的错误。

此外,由于它们不等价,流 API 永远不会将这些值识别为“实际上没有限制”。甚至指定Long.MAX_VALUE意味着流实现必须跟踪已处理元素的数量以确保遵守限制。因此,不添加limit与添加程序员期望永远不会超过的数字的限制相比,操作可以具有显着的性能优势。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有条件地将操作添加到 Java 8 流 的相关文章

随机推荐

  • MVC4 自定义不显眼的验证器不起作用

    不知道出了什么问题 语法似乎是正确的 但它仍然不会在客户端触发 如果我提交表单 我会得到服务器端验证 客户端什么也没有 这是页面上的代码 Scripts jquery validate min js gt Scripts jquery va
  • 如何在matlab中将向量添加到矩阵?

    如何将向量添加到 Matlab 中的矩阵中 以将向量的 i 索引添加到 i 行中的所有成员的方式 例如 A 1 2 3 4 5 6 6 7 8 v 1 2 3 所需的结果是 2 3 4 6 7 8 9 10 11 多谢 您可以使用bsxfu
  • 求大数阶乘​​的快速方法

    这是我的程序 但是对于像 100 000 这样的大数字 它的运行速度非常慢 有什么选项可以优化吗 import java math BigInteger import java util Scanner public class Main
  • python分块三对角矩阵

    我想从三个 numpy ndarray 开始创建一个块三对角矩阵 有没有任何 直接 方法可以在 python 中做到这一点 先感谢您 Cheers 对于 常规 numpy 数组 使用numpy diag http docs scipy or
  • 如何在 for_each 中组合函数和谓词?

    你怎么能打电话给Function over some容器的一部分 使用for each 我创建了一个for each if 做一个 for i in shapes if i color 1 displayShape i 电话看起来像 for
  • 用于挂钩进程函数的 Linux 模块

    我有一个问题 也许你有一些关于这方面的信息 我想在运行进程中挂钩套接字接收函数 recv 并修改传入数据 我怎么知道 我可以使用内核模块来做到这一点 但我找不到有关如何执行此类挂钩的信息 我尝试过其他方法 例如 Netfilter ipta
  • 使用 Alamofire ObjectMapper 映射到 Swift 对象问题显示 nil

    我是 iOS 和 Swift 开发环境的新手 我试图使用 Alamofire 来提取 JSON 并使用 AlamofireObjectMapper 将检索到的 JSON 集合映射回我的 Swift 对象 问题是我可以通过 Alamofire
  • Calendar.getTime() 失败,并显示 java.lang.IllegalArgumentException:MINUTE(对于亚洲/新加坡时区)

    为什么这段代码会失败 目的是删除时间部分 String dateStr 1982 01 01 String timeZoneID Asia Singapore DateFormat dateFormat new SimpleDateForm
  • django图像上传表单

    我在 django 表单和图像上传方面遇到问题 我已经用谷歌搜索 阅读了文档 甚至还提出了问题 但无法找出问题所在 这是我的文件 我的模特 class UserProfile User user with app settings DESI
  • 以编程方式 IIS 6.0 - 创建虚拟目录且未将其设置为应用程序时出现问题

    因此 我以编程方式在 IIS 6 0 中创建虚拟目录 但我遵循有关创建虚拟目录的唯一 MSDN 或其他 文档 但我的文档位于 http msdn microsoft com en us library ms525598 VS 90 aspx
  • 从范围引用但未定义的 LambdaExpression 变量

    我有一个简单的 lambda 表达式 我想编译和调用它 Expression lt Func lt Commands bool gt gt expression c gt c IsValid test 但是当我执行以下操作时 LambdaE
  • 变异下标越界

    我正在尝试从两个插入符号模型输出创建敏感性和特异性的汇总表 并且在我的 for 循环中 当从包含值的名为 models 的列表中查找值时 它会抛出下标越界错误 这是一个完全可重现的示例 Dplyr 的版本是 0 7 0 谢谢 heart l
  • Laravel、AngularJS 和 CORS 的路由问题

    我一直在广泛寻找解决这个问题的方法 我有一个 AngularJS Web 应用程序 其后端实现为 Laravel 4 如下所示 http app mydomain io AngularJS web app http api mydomain
  • 在 x86 32 位中禁用分页

    我试图直接写入物理内存位置 因此我使用汇编函数首先禁用分页 写入值 然后重新启用分页 但由于某种原因 在尝试写入时仍然会触发页面错误价值 据我了解 在x86 32位中 通过翻转cr0中的第32位来打开和关闭分页 所以这是我的汇编函数 mov
  • 使用 robocopy 复制文件(长名称和路径,以及许多空格) - 缺少参数

    我尝试使用 robocopy 复制文件 但 PowerShell 给出错误 MissingArgument robocopy D Enciclopedia mia Tutorial FATTI DA ME Internet Google L
  • 是否可以让您上传的 iPhone 应用程序自动更新? [复制]

    这个问题在这里已经有答案了 我即将将我的 iPhone 应用程序上传到苹果商店 但我打算在不久的将来发布更多版本 一旦我将新版本上传到苹果商店 是否有办法使我的应用程序自动更新 也就是说 我即将上传版本 1 0 一旦我上传版本 1 x 用户
  • 并发字典 AddOrUpdate 与索引添加

    在当前项目中 我可以通过两种方式为并发字典中的现有键分配值 A concurrentDictionary1 key value and B concurrentDictionary2 AddOrUpdate key value k v gt
  • 如何在 Pygame 中获取显示器的分辨率?

    我只是想知道我是否可以在 Pygame 中获取显示器的分辨率 然后使用这些尺寸创建一个窗口 以便启动程序检测显示器分辨率 然后自动将窗口适合全屏屏幕 我目前正在使用pygame display set mode AN INTEGER AN
  • weblogic.jndi.WLInitialContextFactory 类在哪里?

    当尝试执行我的 jar 文件时 出现异常 javax naming NoInitialContextException Cannot instantiate class weblogic jndi WLInitialContextFacto
  • 有条件地将操作添加到 Java 8 流

    我想知道是否可以根据流外部设置的某种条件向流添加操作 例如 我想向流添加限制操作 如果我的limit变量不等于 1 我的代码目前看起来像这样 但我还没有看到以这种方式使用流的其他示例 其中 Stream 对象被重新分配给应用于自身的中间操作