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))
.filter(Boolean::valueOf)
.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?
Stream findFirst() vs findAny() – ConclusionUse findAny() to get any element from any parallel stream in faster time.
The findAny() method returns any element from a Stream, while the findFirst() method returns the first element in a Stream.
The orElse() method of java. util. Optional class in Java is used to get the value of this Optional instance, if present. If there is no value present in this Optional instance, then this method returns the specified value.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With