First, it's worth looking at what a Consumer<String>
actually is. From the documentation:
Represents an operation that accepts a single input argument and
returns no result. Unlike most other functional interfaces, Consumer
is expected to operate via side-effects.
So it's a function that accepts a String and returns nothing.
Consumer<String> p = ""::equals;
Compiles successfully because equals
can take a String (and, indeed, any Object). The result of equals is just ignored.*
p = s -> "".equals(s);
This is exactly the same, but with different syntax. The compiler knows not to add an implicit return
because a Consumer
should not return a value. It would add an implicit return
if the lambda was a Function<String, Boolean>
though.
p = s -> true;
This takes a String (s
) but because true
is an expression and not a statement, the result cannot be ignored in the same way. The compiler has to add an implicit return
because an expression can't exist on its own. Thus, this does have a return: a boolean. Therefore it's not a Consumer
.**
p = s -> ("".equals(s));
Again, this is an expression, not a statement. Ignoring lambdas for a moment, you will see the line System.out.println("Hello");
will similarly fail to compile if you wrap it in parentheses.
*From the spec:
If the body of a lambda is a statement expression (that is, an expression that would be allowed to stand alone as a statement), it is compatible with a void-producing function type; any result is simply discarded.
**From the spec (thanks, Eugene):
A lambda expression is congruent with a [void-producing] function type if ...
the lambda body is either a statement expression
(§14.8)
or a void-compatible block.