13

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?

2
  • 2
    It would be easier to help you if you provided a minimal reproducible example. It should be easy for you to write one - it's easy for everyone else too, but it's better for one person to do it (you) than everyone who wants to help. Commented Oct 1, 2017 at 8:20
  • 2
    @AlexSalauyou: But List.add(E) returns boolean. Commented Oct 1, 2017 at 8:21

2 Answers 2

19

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Ah ok. Thank you. I'll rather just create a new void helper method, still better than an anonymous class. I'll try to make a complete example next time.
@JonSkeet exactly - this is called the special void compatibility rule
Or just put it in a block. I though I had tried that previously but no.. () -> { a.add(x); b.add(y); }
@zedoo: Will add that into the answer now.
A new => operator?
5

Basically your first expression is way to invoke a method but ignore the result:

 aList.add(x) // actually returns a boolean but you ignore this result

This is not anything new for lambdas actually, as it has been like this since java appeared:

List<Integer> list ...
list.add(1); // returns boolean but we ignore the result almost always

So why is the result not ignored in your second example? Well because the JLS says so, as seen here. There are 4 types that will work though:

Method Invocations
Assignments
Increment and Decrement expressions
Class Instance Creation expressions

Your last example uses && which is neither of the 4 types described in the JLS, thus a compile time error.

You could create a helper method to add to both lists(or as you did with Boolean.valueOf):

public static boolean helper(int x) {
    boolean result = first.add(x) && second.add(x);
    return result;
}

And use it:

expectRollback(() -> helper(x))

2 Comments

Or just use a block lambda with an if statement, of course.
Ha, but I'm actually not even interested in the conditional add. (Apart, list.add is true by definition..) I just want to execute both adds. Still, Jon had the right hint, 'void compatible block'. Just use a block!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.