一系列链接的调用和一系列存储中间返回值的调用之间没有语义差异。因此,以下代码片段是等效的:
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
与添加程序员期望永远不会超过的数字的限制相比,操作可以具有显着的性能优势。