Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java findFirst()之前带有sorted()的流不再是惰性的_Java_Java 8_Java Stream - Fatal编程技术网

Java findFirst()之前带有sorted()的流不再是惰性的

Java findFirst()之前带有sorted()的流不再是惰性的,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个元素列表,我需要找到满足条件的第一个元素,然后使用Java8流退出 我认为以下代码不幸地评估了所有不符合我需要的可用元素,我需要逐个评估项目,并在找到第一个匹配项时停止(break): 我在这里对元素进行排序,然后将元素映射到其url属性,然后尝试筛选url是否为空,然后首先查找匹配项 Arrays.stream(dataArray) .sorted(Comparator.comparing(d -> d.getPriority())) .peek(o -> System.o

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

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

我在这里对元素进行排序,然后将元素映射到其
url
属性,然后尝试筛选
url
是否为空,然后首先查找
匹配项

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

排序的
操作强制遍历流中的所有项

有状态操作(如distinct和sorted)可以包含 处理新元素时来自以前看到的元素的状态

有状态操作可能需要在执行之前处理整个输入 产生结果。例如,无法从中产生任何结果 对流进行排序,直到看到流的所有元素

但是,我不确定为什么对流中的所有元素执行排序后的操作

如果单独执行排序,然后将流用于其余的处理,则处理将在找到第一个匹配项时停止,如预期的那样

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

Arrays.stream(dataArray)
.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("");

下面是一个较小的示例,说明了这个问题:

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
PEEK: ab
PEEK: abc
PEEK: abcd
如果排序的
行未注释,则输出为:

PEEK: ab
PEEK: ab
PEEK: abc
PEEK: abcd
(正如预期的那样,在这两种情况下,整个管道的最终结果都是“ab”。)

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

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


最终结果是正确的,但行为是意外的。这可能被认为是一个bug。如果合适,我将调查并提交一个bug。

您想要使用的是
stream.collect(minBy(…)
。它具有线性性能


minBy
静态方法可以在
Collectors
类中找到。

我同意你的观点,尤其是如果任何
中间
流操作是昂贵的操作。(在我的问题中,
getOriginalURL
是一个昂贵的!是的,性能错误。归档。@MuhammadHewedy很好的捕获,顺便说一句。谢谢你提出这个问题。@StuartMarks我很好奇-你怎么知道它是一个错误?你检查过这个行为没有其他逻辑解释吗?@Eran,我看了源代码(,第301-308行)查看排序后它是否无条件地将所有元素向下推。这似乎是错误的,因为
findFirst
应该是短路。然后我问实现它的人,他说:“是的,这是一个性能缺陷。”:-)