Java 8中的Stream anyMatch()会遍历整个流程。

4

给定以下三个函数:

private Optional<Integer> abc() {
    return Optional.of(6);
}


private Optional<Integer> def() {
    return Optional.of(3);
}


private Optional<Integer> ghi() {
    return Optional.of(9);
}

如果我想检查这三个函数之一是否返回大于5的内容(当然是包装在Optional中的),在传统命令式风格下,我会像这样处理:

if( abc().get() > 5 || def().get() > 5 || ghi().get() > 5) {
  ......// Do something
 }  // I am not doing get() without checking ifPresent() just for simplicity sake

这种方法只会进入 abc() 函数并跳过 def()ghi(),因为第一个表达式返回真值。这是一种很好的优化。 现在如果我使用流(Streams)以函数式编程风格编写相同的代码,
if( Stream.of(abc(), def(), ghi()).anyMatch(integer -> integer.get() > 5)) {
   .........
}

我原本以为只会调用 abc() 函数,但实际上三个函数都被调用了。既然使用了 anyMatch() 方法,检查其他两个函数是否满足条件是不是多余的呢?
同样道理,在使用 noneMatch() 时也是这样,整个 Stream 都会被遍历。我想知道的是:即使在第一个元素满足条件的情况下,遍历整个 Stream(特别是 Stream 中有很多值的情况下)是否真的是一件坏事?

4
当你使用 Stream.of(abc(), def(), ghi()) 时,你正在调用这三个方法。 - fps
相关链接:https://dev59.com/8F4b5IYBdhLWcg3wrzXY - Holger
感谢 @Holger。等待使用Java 9 :D - pvpkiran
3个回答

4
这是因为Stream#of先于Stream#anyMatch,所以所有方法都会被调用,因为它们先于Stream#of发生。
你可以使用Supplier<Optional<Integer>>使Stream#anyMatch在实际方法调用之前执行,例如:
// Note: it just create Suppliers and actual method is called on demand 
Stream<Supplier<Optional<Integer>>> values=Stream.of(this::abc,this::def,this::ghi);

if(values.anyMatch(integer -> integer.get().get() > 5)) {
    .........
}

如@FedericoPeraltaSchaffner所提到的,Optional可能为空,你可以使用Optional#orElse(0)代替Optional#get,或者使用Optional#filter(it -> it > 5).isPresent()

编辑

为了说明Stream的短路终端操作,你应该使用lambda表达式/方法引用,因为方法调用发生在Stream#of之前,例如:
Supplier<Optional<Integer>> failsOnMismatched = () -> { 
   throw new IllegalStateException(); 
};

// the instantiation of method reference happen before `Stream#of`,
// but the linked method is called on demand.
//                 v 
if(Stream.of(this::abc, failsOnMismatched).anyMatch(it -> it.get().orElse(0) > 5)){
  //reached
}

//it is failed since the value of def() <= 5 ---v
if(Stream.of(this::def, failsOnMismatched).anyMatch(it -> it.get().orElse(0) > 5)){
  //unreachable
}

3
如果您使用的是Java 9或更高版本,您可以链接Optionals,应用Optional.filterOptional.orOptional.ifPresent
abc().filter(n -> n > 5)
    .or(() -> def().filter(n -> n > 5))
    .or(() -> ghi().filter(n -> n > 5))
    .ifPresent(n -> {
        // do domething
    });

请注意,此解决方案是完整的,即您不需要检查任何值是否存在,因为这已经由Optional.filterOptional.orOptional.ifPresent完成。

1

Stream#anyMatch可能不会对谓词中的所有特定元素进行评估。但是,同时of也期望参数,这意味着它们将首先被评估。

返回此流中是否有任何元素与提供的谓词匹配。如果不必要确定结果,则可能不会在所有元素上评估谓词。如果流为空,则返回false并且不评估谓词。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接