Home » Java » findAny orElse after filter

findAny orElse after filter

Posted by: admin December 28, 2021 Leave a comment


I’m using Stream filter findAny.orElse, but it’s not working as I expect, so I presume I’m not understanding how really works.
Here my code

return Stream.of(getObjectAttributeValue(product, matchCriteria.getFieldName()))
             .map(o -> isIngredientRestricted(matchCriteria, (List<String>) o))
             .findAny().orElse(isCommercialHierarchyInfoRestricted(product, matchCriteria));

Basically what I was expecting was that if the first map emit a Boolean false, then it will be filter so then the findAny would not find any optional, so the orElse would be invoked. But even having a true in the filter the isCommercialHierarchyInfoRestricted is invoked.

Any idea what I’m doing wrong?


You actually need to use orElseGet:

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

In Java method argument is always evaluated prior to method call even if it’s unnecessary inside the method, so you cannot avoid evaluating the orElse argument. That’s why orElseGet exists: its argument is the function and the function can be not executed at all when it’s not necessary.


As Tagir explained, using orElse(expression) always causes the evaluation of expression before invoking the method orElse and you have to use orElseGet(() -> expression) instead to defer the evaluation of the expression.

However, this is an unnecessary use of the Stream API. If you want to evaluate a single item, you don’t need to create a single-element stream just to call findAny afterwards. You can create an Optional in the first place:

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

However, even that is an unnecessary complication compared to the equivalent ordinary Java language construct:

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

This does exactly the same without the need for additional APIs nor lambda expressions. The || operator also guarantees that the second expression won’t get evaluated, if the first one evaluates to true.