Stream of boolean values, is any true?

JavaLambdaParallel ProcessingJava 8Java Stream

Java Problem Overview


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))

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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))

Solution 3 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionS1lentSt0rmView Question on Stackoverflow
Solution 1 - JavaMarko TopolnikView Answer on Stackoverflow
Solution 2 - JavaHolgerView Answer on Stackoverflow
Solution 3 - JavaGeorgianView Answer on Stackoverflow