I possibly use the wrong terms, feel free to correct.
I have a test method which takes a Runnable
:
void expectRollback(Runnable r) { .. }
I can call this method like this:
expectRollback(() -> aList.add(x))
Cool, I understand lambdas! This is awesome. Let's be super clever...
expectRollback(() -> aList.add(x) && bList.add(y))
But what? That doesn't compile: 'void' methods cannot return a value.
Doesn't the first call also return a value though? What is the difference between the first and the second call?
It's subtle, but I think I've got it.
In JLS 15.27.3 we have:
A lambda expression is congruent with a function type if all of the following are true:
- ...
- If the lambda parameters are assumed to have the same types as the function type's parameter types, then:
- If the function type's result is
void
, the lambda body is either a statement expression (ยง14.8) or a void-compatible block.- ...
- ...
Now aList.add(x)
is a statement expression, but aList.add(x) && bList.add(y)
is not. You can see that without any lambdas involved - just try to use them as statements:
aList.add(x); // Fine
aList.add(x) && bList.add(y); // Error: "not a statement"
If you wrap that expression in a method call, it's fine, because the method call is a statement expression again:
rollback(() -> Boolean.valueOf(aList.add(x) && bList.add(y)));
I'm not actually suggesting you do that - just trying to explain why that would work but your previous attempt didn't.
If we assume that List.add
really will return true
every time as documented, just use a block lambda:
rollback(() -> { aList.add(x); bList.add(y); });
I'd argue that's clearer anyway as it makes it more obvious that you don't care about the value returned by the first add
call.
See more on this question at Stackoverflow