我正在使用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。
知道我做错了吗?
答案 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
。