Java 8 Stream anyMatch()遍历整个流

时间:2018-01-27 09:59:29

标签: java-8 java-stream

给出三个这样的函数:

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(),因为第一个表达式返回true。这是一个很好的优化。 现在,如果我使用Streams以功能样式编写相同内容,

if( Stream.of(abc(), def(), ghi()).anyMatch(integer -> integer.get() > 5)) {
   .........
}

我认为会发生同样的情况,即只会调用abc()。但它调用了所有三个功能。当有anyMatch()时,检查其他两个函数是不是多余的?

noneMatch()的情况相同;流程贯穿整个流程。我只是想知道:遍历整个流是否真的是一件坏事(特别是如果流有很多值),即使在第一个元素满足条件也是如此?

3 个答案:

答案 0 :(得分:2)

这是因为Stream#of happens before Stream#anyMatch,所以所有方法都会被调用,因为它们发生在Stream#of之前。

您可以使用Stream#anyMatch在实际方法调用之前发生Supplier<Optional<Integer>>,例如:

// 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,或使用Opitional#filter(it -> it > 5).isPresent()

修改

为了说明Stream的短路终端操作,你应该使用lambdas /方法引用表达式,因为方法调用发生在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
}

答案 1 :(得分:2)

如果您使用的是Java 9或更高版本,则可以链接选项,应用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完成。

答案 2 :(得分:0)

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

  

返回此流的任何元素是否与提供的元素匹配   谓语。 如果不是,则可能无法评估所有元素的谓词   确定结果所必需的 。如果流是空的那么   返回false并且不评估谓词。