java - 在 findFirst() 之前使用 sorted() 流式传输不再懒惰

标签 java java-8 java-stream

我有一个元素列表,我需要找到满足条件的第一个元素,然后使用 Java 8 流退出。

我认为下面的代码不幸地评估了所有不是我需要的可用元素,我需要一个一个地评估项目并在找到第一个匹配项时停止(break):

我在这里对元素进行排序,然后将元素映射到它的 url 属性然后尝试过滤如果 url 不为 null 或为空然后首先找到 匹配!

Arrays.stream(dataArray)
.sorted(Comparator.comparing(d -> d.getPriority()))
.peek(o -> System.out.println("SORT: " + o))
.map(d -> d.getOriginalURL(shortUrl))
.peek(o -> System.out.println("MAP: " + o))
.filter(u -> u != null && !u.isEmpty())
.peek(o -> System.out.println("FILTER: " + o))
.findFirst().orElse("");

但输出显示,即使第一个匹配 if 条件 (filter) 操作,所有项目都会被评估。

Data[] data = new Data[] { new ParseData(), new InMemoryData() };
System.out.println(">>> " + getOriginalURL(data, ""));

输出:

SORT: mhewedy.usingspark.data.InMemoryData@7adf9f5f
MAP: InMemory URL
FILTER: InMemory URL
SORT: mhewedy.usingspark.data.ParseData@85ede7b
MAP: Parse.com URL         <<< THIS SHOULD NOT HAPPEN
FILTER: Parse.com URL      <<< AND THIS TOO
>>> InMemory URL

如输出所示,当过滤器与第一个元素匹配时,流不会停止,而是继续评估第二个元素!

我想这样做:

Arrays.sort(dataArray, Comparator.comparing(d -> d.getPriority())); // sort

for (Data data : dataArray) {
    String url = data.getOriginalURL(shortUrl);           // map
    if (url != null && !url.isEmpty()) {                  // filter
        System.out.println("url :" + url);            
        return url;                                   // find first
    }
}

最佳答案

这是一个说明问题的小例子:

Stream.of("a", "ab", "abc", "abcd")
    // .sorted() // uncomment and what follows becomes eager
    .filter(s -> s.contains("b"))
    .peek(s -> System.out.println("PEEK: " + s))
    .findFirst()
    .orElse("X");

正如预期的那样,输出是:

PEEK: ab

如果 sorted 行未注释,则输出为:

PEEK: ab
PEEK: abc
PEEK: abcd

(如预期的那样,整个流水线的最终结果在两种情况下都是“ab”。)

的确,sorted 必须在生成第一个输出元素之前消耗所有输入。从这个意义上说,它是渴望的。但是,它会影响元素向下游发送的方式,这看起来确实很奇怪。

如果不进行排序,findFirst 操作会从上游“拉取”元素,直到找到一个元素,然后停止。通过排序,sorted() 操作急切地收集所有元素,对它们进行排序,并且由于它们都在那里,它会将它们“推”到流中。当然,findFirst 会忽略除第一个元素以外的所有元素。但这意味着干预操作(例如过滤器)可能会做不必要的工作。

最终的结果是正确的,但是行为是出乎意料的。这可能被认为是一个错误。如果合适,我会调查并提交错误。

关于java - 在 findFirst() 之前使用 sorted() 流式传输不再懒惰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23419223/

相关文章:

java - 如何在保存到磁盘之前验证 ZipFile 的内容

java - 动态改变 Akka Streams 的节流级别

java 8 Docker 错误指定的 VM 选项 'InitialRAMPercentage=XX'

java - 如何使用 Stream API 展平此 List<C1>,其中 C1 包含单个元素的 C2 集合?

java - 在 Android SQLite 表中返回 Count(*)

java - 如何计算时间戳范围之间的总小时数和分钟数(在特定范围内)

java - 使用流内的流检查进行过滤

java - 使用流总结列表

Java Streams - 将两个字符串行分别映射到一个对象

Java 8 流和简单类型