gpt4 book ai didi

java - Java 8 流惰性在实践中没有用吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:27:25 27 4
gpt4 key购买 nike

我最近阅读了很多关于 Java 8 流的文章,还有几篇关于使用 Java 8 流延迟加载的文章:hereover here .我似乎无法摆脱这样一种感觉,即延迟加载完全没有用(或者充其量只是提供零性能值(value)的次要语法便利)。

我们以这段代码为例:

int[] myInts = new int[]{1,2,3,5,8,13,21};

IntStream myIntStream = IntStream.of(myInts);

int[] myChangedArray = myIntStream
.peek(n -> System.out.println("About to square: " + n))
.map(n -> (int)Math.pow(n, 2))
.peek(n -> System.out.println("Done squaring, result: " + n))
.toArray();

这将登录控制台,因为调用了终端操作,在本例中为toArray(),我们的流是惰性的,仅在终端运行时执行操作被调用。当然我也可以这样做:

  IntStream myChangedInts = myIntStream
.peek(n -> System.out.println("About to square: " + n))
.map(n -> (int)Math.pow(n, 2))
.peek(n -> System.out.println("Done squaring, result: " + n));

并且不会打印任何内容,因为 map 没有生成,因为我不需要数据。直到我这样称呼:

  int[] myChangedArray = myChangedInts.toArray();

瞧,我得到了映射数据和控制台日志。除了我认为它没有任何好处。我意识到我可以在调用 toArray() 之前很久就定义过滤器代码,并且我可以绕过这个“没有真正过滤的流”,但那又怎样? 这是唯一的好处吗?

文章似乎暗示懒惰会带来性能提升,例如:

In the Java 8 Streams API, the intermediate operations are lazy and their internal processing model is optimized to make it being capable of processing the large amount of data with high performance.

Java 8 Streams API optimizes stream processing with the help of short circuiting operations. Short Circuit methods ends the stream processing as soon as their conditions are satisfied. In normal words short circuit operations, once the condition is satisfied just breaks all of the intermediate operations, lying before in the pipeline. Some of the intermediate as well as terminal operations have this behavior.

这听起来确实像是跳出循环,与懒惰无关。

最后,第二篇文章中有这么一句令人费解的台词:

Lazy operations achieve efficiency. It is a way not to work on stale data. Lazy operations might be useful in the situations where input data is consumed gradually rather than having whole complete set of elements beforehand. For example consider the situations where an infinite stream has been created using Stream#generate(Supplier<T>) and the provided Supplier function is gradually receiving data from a remote server. In those kind of the situations server call will only be made at a terminal operation when it's needed.

不处理过时的数据?什么?延迟加载如何避免处理陈旧数据?


TLDR:除了能够在以后运行过滤器/映射/缩减/任何操作(提供零性能优势)之外,延迟加载还有什么好处吗?

如果是这样,什么是真实世界的用例?

最佳答案

您的终端操作 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 不是)使这种优化成为可能。

关于java - Java 8 流惰性在实践中没有用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52685535/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com