Stream of boolean values, is any true?
I want to parallelize the following code snipped using a parallelStream:
boolean anyTrue() {
for (Element e : setOfE) {
if (eval(e)) {
return true;
}
}
return false;
}
Will the following work on parallel streams and use regular short-circuit evaluation?
setOfE.parallelStream().map(e -> eval(e)).reduce(false, (a,b) -> a || b))
Streams API actually has first-class support for your requirement:
setOfE.parallelStream().anyMatch(e->eval(e));
As opposed to your approach with reduce
, this is guaranteed to have short-circuit evaluation and optimally leverage parallelism.
No, reduction does not support short-circuit evaluation. The reason is that reduce
just receives an arbitrary BinaryOperator
implementation and has no idea about the possibilities of short-circuiting the particular operation.
But you can perform the entire operation much simpler:
setOfE.parallelStream().filter(e -> eval(e)).findAny().isPresent()
This simply searches for an arbitrary item for which eval
returns true
and findAny
allows to end the operation as soon as one thread has encountered a match. The resulting Optional
can be queried for being empty as you are not interested in the particular matching Element
.
Alternatively you can use as suggested by Marko Topolnik’s comment:
setOfE.parallelStream().anyMatch(e -> eval(e))
I have a case where I DON'T want to short-circuit my operations.
I need to process all my values, then the final result of the stream should be an anyMatch
, basically. But I can't actually use anyMatch
, because that will short-circuit as soon as it finds a true
value.
// WRONG for my case - need to process ALL field IDs
return fieldIs.stream()
.map(UUID::toString)
.anyMatch(fieldId -> processProjectForField(portfolioId, fieldId, projectId, fieldValueDataMap));
// RIGHT for my case - goes through all field IDs, and returns TRUE
// if there is at least one 'true' return from the processProjectForField method.
return fieldIs.stream()
.map(UUID::toString)
.map(fieldId -> processProjectForField(portfolioId, fieldId, projectId, fieldValueDataMap))
.reduce(Boolean.FALSE, Boolean::logicalOr);
// What you wrote is also acceptable
[...]
.reduce(false, (a,b) -> a || b));
// Another way of doing it
[...]
.collect(Collectors.reducing(Boolean.FALSE, Boolean::logicalOr));]
More inspiration here.