Java streams, cannot convert from Optional to Boolean

So my situation is that I have a Boolean evaluator. Essentially, they are all of the custom type BooleanExpression. Each value has a method .evaluate(context), which takes in a map of variables context, and applies the evaluation. Evaluate always returns a Boolean.

I am trying to specifically use Java streams to output this data. So far, I have been able to use Java Streams to apply the .evaluate to every BooleanExpression in a list of List<BooleanExpression>:

return expressions.stream().map(e -> e.evaluate(context)).collect(Collectors.toList());

It works fine and returns something like [true, true, false].

What I am trying to do now is use stream().reduce to take the conjunction of every element in that list. If I have a list of [true, false, false] I want to end up with false.

Here is the code I have so far:

return expressions.stream().reduce((x, y) -> x.evaluate(context) && y.evaluate(context));

It should return a Boolean. But, it’s giving me an error:

Java streams: cannot convert from Optional<BooleanExpression> to Boolean.

I’m not sure what I’m doing wrong here. Could anyone lend some advice?

Answer

The overload of reduce that you are using returns an Optional<BooleanExpression> because in the case of an empty stream, it can return Optional.empty() to indicate that there is nothing to reduce.

Also, that overload is supposed to take a BinaryOperator<BooleanExpression>, which you don’t seem to be giving it. You are giving it a BiFunction<BooleanExpression, BooleanExpression, Boolean>. The lambda you used takes two boolean expressions and returns a boolean.

To fix this. You can first map everything to booleans, then reduce with Boolean::logicalAnd. You also need to specify a default value to return if the stream is empty:

return expressions.stream().map(x -> x.evaluate(context))
                           .reduce(Boolean::logicalAnd)
                           .orElse(true); // value to return if stream is empty

Alternatively, you can use the other overload of reduce that accepts an identity element, and pass in the identity for conjunction (true):

return expressions.stream().map(x -> x.evaluate(context))
                           .reduce(true, Boolean::logicalAnd);

This will return true if the stream is empty.

One more way is to use the third overload of reduce, that takes an identity, a BiFunction, as well as a combiner:

return expressions.stream().reduce(
    true, 
    (x, y) -> x && y.evaluate(context),
    Boolean::logicalAnd);

This will return true if the stream is empty.

Leave a Reply

Your email address will not be published. Required fields are marked *