zedoo zedoo - 3 years ago 170
Java Question

Adding elements to different collections in a single lambda expression

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?

Answer Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download