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>
toBoolean
.
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 boolean
s, 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.