3 回答
TA贡献1780条经验 获得超3个赞
您的终端操作 ,toArray()可能支持您的论点,因为它需要流的所有元素。
一些终端操作没有。而对于这些,如果不是懒惰地执行流,那将是一种浪费。两个例子:
//example 1: print first element of 1000 after transformations
IntStream.range(0, 1000)
.peek(System.out::println)
.mapToObj(String::valueOf)
.peek(System.out::println)
.findFirst()
.ifPresent(System.out::println);
//example 2: check if any value has an even key
boolean valid = records.
.map(this::heavyConversion)
.filter(this::checkWithWebService)
.mapToInt(Record::getKey)
.anyMatch(i -> i % 2 == 0)
第一个流将打印:
0
0
0
也就是说,中间操作将只在一个元素上运行。这是一个重要的优化。如果不是懒惰,那么所有peek()调用都必须在所有元素上运行(绝对没有必要,因为您只对一个元素感兴趣)。中间操作可能很昂贵(例如在第二个示例中)
短路端子操作(toArray不是)使这种优化成为可能。
TA贡献1757条经验 获得超8个赞
惰性对于 API 的用户非常有用,尤其是当Stream管道评估的最终结果可能非常大时!
简单的例子是Files.linesJava API 本身中的方法。如果您不想将整个文件读入内存并且只需要第一N行,那么只需编写:
Stream<String> stream = Files.lines(path); // lazy operation
List<String> result = stream.limit(N).collect(Collectors.toList()); // read and collect
TA贡献2003条经验 获得超2个赞
我有一个来自我们代码库的真实示例,因为我将对其进行简化,但不完全确定您可能喜欢它还是完全掌握它...
我们有一个需要 的服务List<CustomService>
,我想称之为。现在为了调用它,我要去一个数据库(比现实简单得多)并获得一个List<DBObject>
; 为了从中获得a List<CustomService>
,需要进行一些重大的转换。
这是我的选择,就地转换并传递列表。很简单,但可能不是那么理想。第二种选择,重构服务,接受 aList<DBObject>
和 a Function<DBObject, CustomService>
。这听起来微不足道,但它使懒惰(除其他外)成为可能。该服务有时可能只需要该 List 中的几个元素,或者有时需要max
某个属性等 - 因此我不需要对所有元素进行大量转换,这就是Stream API
基于拉的懒惰是赢家的地方。
在 Streams 出现之前,我们曾经使用guava
. 它也Lists.transform( list, function)
很懒惰。
这不是流的基本特征,即使没有番石榴也可以完成,但这样要简单得多。这里提供的例子findFirst
很好,而且最容易理解;这就是懒惰的全部意义所在,元素仅在需要时才被拉取,它们不会从一个中间操作以块的形式传递到另一个操作,而是一次从一个阶段传递到另一个阶段。
添加回答
举报