过滤后查找任何orElse

pau*_*aul 4 java optional java-8 java-stream

我正在使用Stream过滤器findAny.orElse,但它没有像我期望的那样工作,所以我认为我不理解它是如何工作的.在这里我的代码

return Stream.of(getObjectAttributeValue(product, matchCriteria.getFieldName()))
             .map(o -> isIngredientRestricted(matchCriteria, (List<String>) o))
             .filter(Boolean::valueOf)
             .findAny().orElse(isCommercialHierarchyInfoRestricted(product, matchCriteria));
Run Code Online (Sandbox Code Playgroud)

基本上我所期望的是,如果第一个地图发出布尔值false,那么它将被过滤,因此findAny将找不到任何可选项,因此将调用orElse.但即使在过滤器中有一个true,也会调用isCommercialHierarchyInfoRestricted.

知道我做错了什么吗?

Tag*_*eev 6

你实际上需要使用orElseGet:

.findAny().orElseGet(() -> isCommercialHierarchyInfoRestricted(product, matchCriteria));
Run Code Online (Sandbox Code Playgroud)

在Java方法中,始终在方法调用之前计算参数,即使在方法内部不必要,因此您无法避免评估orElse参数.这就是orElseGet存在的原因:它的参数是函数,并且在没有必要时根本不执行函数.


Hol*_*ger 6

正如Tagir所解释的那样,使用orElse(expression)始终会expression在调用方法之前进行评估,orElse而您必须使用它orElseGet(() -> expression)来推迟对表达式的求值.

但是,这是StreamAPI 的不必要使用.如果要评估单个项目,则不需要创建单个元素流,只是为了findAny之后调用.你可以Optional在第一时间创建一个:

return Optional.of(getObjectAttributeValue(product, matchCriteria.getFieldName()))
     .map(o -> isIngredientRestricted(matchCriteria, (List<String>)o))
     .filter(b -> b)
     .orElseGet(() -> isCommercialHierarchyInfoRestricted(product, matchCriteria));
Run Code Online (Sandbox Code Playgroud)

但是,与同等的普通Java语言构造相比,即使这是一个不必要的复杂问题:

return isIngredientRestricted(matchCriteria,
           (List<String>)getObjectAttributeValue(product, matchCriteria.getFieldName()))
  ||  isCommercialHierarchyInfoRestricted(product, matchCriteria);
Run Code Online (Sandbox Code Playgroud)

这完全相同,无需额外的API或lambda表达式.该||运营商还保证了第二个表达式将不会得到评估,如果第一个计算结果为true.

  • 是的,有时我们希望使用更多我们需要的功能编程.我不像以前那样使用Stream恢复. (2认同)