为什么消费者接受带有语句体而不是表达式体的 lambda 表达式? [英] Why do Consumers accept lambdas with statement bodies but not expression bodies?
问题描述
下面的代码出人意料地编译成功了:
The following code surprisingly is compiling successfully:
Consumer<String> p = ""::equals;
这也是:
p = s -> "".equals(s);
但是这失败了,错误 boolean cannot be convert to void
如预期的那样:
But this is fails with the error boolean cannot be converted to void
as expected:
p = s -> true;
用括号修改第二个例子也失败了:
Modification of the second example with parenthesis also fails:
p = s -> ("".equals(s));
是 Java 编译器中的错误还是有我不知道的类型推断规则?
Is it a bug in Java compiler or is there a type inference rule I don't know about?
推荐答案
首先,值得看看 Consumer
实际上是什么.来自文档:
First, it's worth looking at what a Consumer<String>
actually is. From the documentation:
表示一个操作,接受单个输入参数并且不返回任何结果.与大多数其他功能接口不同,Consumer预计通过副作用起作用.
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;
编译成功,因为 equals
可以接受一个字符串(实际上,任何对象).equals 的结果只是被忽略了.*
Compiles successfully because equals
can take a String (and, indeed, any Object). The result of equals is just ignored.*
p = s -> "".equals(s);
这是完全相同的,但语法不同.编译器知道不添加隐式 return
因为 Consumer
不应该返回值.如果 lambda 是一个Function
,它会添加一个隐式的return
.
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;
这需要一个字符串 (s
) 但因为 true
是一个表达式而不是一个语句,结果不能以同样的方式被忽略.编译器必须添加一个隐式的return
,因为表达式不能单独存在.因此,这个确实有一个返回值:一个布尔值.因此它不是 Consumer
.**
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));
同样,这是一个表达式,而不是一个语句.暂时忽略 lambda 表达式,您将看到 System.out.println("Hello");
如果将其括在括号中,同样将无法编译.
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.
*来自规范一个>:
如果 lambda 的主体是语句表达式(即,允许作为语句独立的表达式),则它与产生 void 的函数类型兼容;任何结果都被简单地丢弃.
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):
一个 lambda 表达式与一个 [void-produce] 函数类型是全等的,如果 ...lambda 主体是语句表达式(§14.8)或者一个兼容空的块.
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.
这篇关于为什么消费者接受带有语句体而不是表达式体的 lambda 表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!