Im reading Java 8 in Action. In section 3.5.2 there is a paragraph about 'void-compatibility rule':
If a lambda has a statement expression as its body, it’s compatible
with a function descriptor that returns void (provided the parameter
list is compatible too). For example, both of the following lines are
legal even though the method add of a List returns a boolean and not
void as expected in the Consumer context (T -> void):
// Predicate has a boolean return
Predicate<String> p = s -> list.add(s);
// Consumer has a void return
Consumer<String> b = s -> list.add(s);
How would you describe 'statement expression' in general? I thought it was either statement or expression. Also this void-compatibility rule is not 100% clear to me, can you think of any other examples?
The term “statement expression” or “expression statement” refers to expressions that are also allowed to be used as a statement. They are described in the Java Language Specification, §14.8. Expression Statements.
They include:
- Method Invocations
- Assignments
- Increment/Decrement expressions
- Class Instance Creation expressions
So other examples are:
Consumer<String> b = s -> counter++;
Function<String,Integer> f = s -> counter++;
or
Consumer<String> b = s -> new BigDecimal(s);
Function<String,BigDecimal> f = s -> new BigDecimal(s);
As a rule of thumb, a lambda expression of the form x -> expression
is only legal for a Consumer
(or void
function type in general), if x -> { expression; }
would be legal too.
It is explained in the previous post clearly... I am trying in my way!!!
A function descriptor with explicit return value can be supplied for a lambda function descriptor which is do not return any value.
For Example,
Predicate T -> vs Consumer T -> void
lambda expression which takes an input and gives boolean as return, Predicate, can be supplied for Consumer.
In the following example, public boolean add(E e) {} returns boolean, but it can be used in the lambda for Consumer, which returns void.
Predicate<String> p = s -> list.add(s);
p.test("helloworld"); // this returns boolean
Consumer<String> consumerExample = s -> list.add(s);
consumerExample.accept("Welcometokpm"); // this returns void
The common structure of lambda expression is that:
(parameter) -> {body};
{body} with a single line statement return statement is optional e.g.
Predicate<String> p = s -> list.add(s);
When braces are used return statement becomes mandatory e.g.
Predicate<String> p = s -> { return list.add(s);};
Now, consider a Functional Interface like Consumer with an abstract method which doesn't return any value. It can accept a statement which returns any value because compiler ignores return statement for such abstract methods.
And hence below statements holds true:
Consumer<String> b = s -> list.add(s);
Equivalent to:
Consumer<String> consumerExample = s -> {list.add(s);};
Below line is incorrect:
Consumer<String> consumerExample = s -> {return list.add(s);};
Therefore, if a lambda has statement expression as its body, its compatible with a function descriptor that returns void (provided that parameter list is compatible too).