过滤后查找任何orElse

时间:2016-01-04 09:37:00

标签: java java-8 java-stream optional

我正在使用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));

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

知道我做错了吗?

2 个答案:

答案 0 :(得分:6)

您实际上需要使用orElseGet

.findAny().orElseGet(() -> isCommercialHierarchyInfoRestricted(product, matchCriteria));

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

答案 1 :(得分:6)

作为Tagir explained,在调用方法orElse(expression)之前,使用expression始终会导致orElse的评估,而您必须使用orElseGet(() -> expression)来推迟评估表达。

但是,这是对Stream API的不必要使用。如果要评估单个项目,则不需要创建单个元素流,之后只需调用findAny。您可以在第一时间创建Optional

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

然而,与同等的普通Java语言结构相比,即使这是一个不必要的复杂因素:

return isIngredientRestricted(matchCriteria,
           (List<String>)getObjectAttributeValue(product, matchCriteria.getFieldName()))
  ||  isCommercialHierarchyInfoRestricted(product, matchCriteria);

这完全相同,无需额外的API或lambda表达式。 ||运算符还保证第二个表达式不会被评估,如果第一个表达式的计算结果为true