gpt4 book ai didi

java - Java 流是否能够从 map /过滤器条件中懒惰地减少?

转载 作者:行者123 更新时间:2023-12-05 01:54:23 25 4
gpt4 key购买 nike

我正在使用函数式编程风格来解决 Leetcode 简单问题,Count the Number of Consistent Strings .这道题的前提很简单:统计“所有值都在另一个集合中”的谓词成立的值的数量。

我有两种方法,一种我相当确定其行为符合我的要求,另一种我不太确定。两者都产生正确的输出,但理想情况下,它们会在输出处于最终状态后停止评估其他元素。


    public int countConsistentStrings(String allowed, String[] words) {
final Set<Character> set = allowed.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.toCollection(HashSet::new));
return (int)Arrays.stream(words)
.filter(word ->
word.chars()
.allMatch(c -> set.contains((char)c))
)
.count();
}

在这个解决方案中,据我所知,allMatch 语句将在谓词不成立的第一个 c 实例处终止并评估为 false,跳过该流中的其他值。


    public int countConsistentStrings(String allowed, String[] words) {
Set<Character> set = allowed.chars()
.mapToObj(c -> (char)c)
.collect(Collectors.toCollection(HashSet::new));
return (int)Arrays.stream(words)
.filter(word ->
word.chars()
.mapToObj(c -> set.contains((char)c))
.reduce((a,b) -> a&&b)
.orElse(false)
)
.count();
}

在此解决方案中,使用了相同的逻辑,但我使用了 map,然后是 reduce,而不是 allMatch。从逻辑上讲,在单个 false 值来自 map 阶段后,reduce 将始终评估为 false。我知道 Java 流是懒惰的,但我不确定它们何时“知道”它们可以有多懒惰。这会比使用 allMatch 效率低吗?或者懒惰会确保相同的操作吗?


最后,在这段代码中,我们可以看到 x 的值将始终为 0,因为在仅过滤正数之后,它们的总和将始终为正(假设没有溢出)所以取最小的正数和硬编码的 0 将是 0。流是否足够懒惰以始终将其评估为 0,或者它会在过滤器之后减少每个元素吗?

List<Integer> list = new ArrayList<>();
...
/*Some values added to list*/
...
int x = list.stream()
.filter(i -> i >= 0)
.reduce((a,b) -> Math.min(a+b, 0))
.orElse(0);

综上所述,如何知道 Java 流何时会惰性化?我在代码中看到了偷懒的机会,但我如何保证我的代码尽可能地偷懒?

最佳答案

您要求的实际术语是 short-circuiting

Further, some operations are deemed short-circuiting operations. An intermediate operation is short-circuiting if, when presented with infinite input, it may produce a finite stream as a result. A terminal operation is short-circuiting if, when presented with infinite input, it may terminate in finite time. Having a short-circuiting operation in the pipeline is a necessary, but not sufficient, condition for the processing of an infinite stream to terminate normally in finite time.

术语“懒惰”仅适用于中间操作,意味着它们仅在终端操作请求时才执行工作。情况总是如此,因此当您不链接终端操作时,任何中间操作都不会处理任何元素。

判断一个终端操作是否短路,很简单。转到 the Stream API documentation并检查特定终端操作的文档是否包含句子

This is a short-circuiting terminal operation.

allMatch has it , reduce has not .

这并不意味着这种基于逻辑或代数的优化是不可能的。但责任在于 JVM 的优化器,它可能会为循环做同样的事情。但是,这需要内联所有涉及的方法以确保此条件始终适用并且没有必须保留的副作用。这种行为兼容性意味着即使处理得到优化,peek(System.out::println) 也会继续打印所有元素,就好像它们已被处理一样。实际上,您不应该期待这样的优化,因为 Stream 实现代码对于优化器来说太复杂了。

关于java - Java 流是否能够从 map /过滤器条件中懒惰地减少?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70673795/

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