Zef*_*ick 61 java lambda type-inference java-8
以下代码令人惊讶地成功编译:
Consumer<String> p = ""::equals;
Run Code Online (Sandbox Code Playgroud)
这个也是:
p = s -> "".equals(s);
Run Code Online (Sandbox Code Playgroud)
但是这会因boolean cannot be converted to void预期错误而失败:
p = s -> true;
Run Code Online (Sandbox Code Playgroud)
使用括号修改第二个示例也会失败:
p = s -> ("".equals(s));
Run Code Online (Sandbox Code Playgroud)
它是Java编译器中的错误还是我不知道的类型推断规则?
Mic*_*ael 80
首先,值得看一下Consumer<String>实际情况.从文档:
表示接受单个输入参数但不返回结果的操作.与大多数其他功能接口不同,消费者需要通过副作用进行操作.
所以这是一个接受String并且不返回任何内容的函数.
Consumer<String> p = ""::equals;
Run Code Online (Sandbox Code Playgroud)
编译成功因为equals可以采用String(实际上是任何Object).等于的结果只是被忽略了.*
p = s -> "".equals(s);
Run Code Online (Sandbox Code Playgroud)
这完全相同,但语法不同.编译器知道不添加隐式,return因为a Consumer不应返回值.如果lambda是a,它会添加一个隐含return的Function<String, Boolean>.
p = s -> true;
Run Code Online (Sandbox Code Playgroud)
这需要一个String(s),但因为它true是一个表达式而不是一个语句,所以不能以相同的方式忽略结果.编译器必须添加隐式,return因为表达式本身不能存在.因此,这确实有一个返回:布尔值.因此它不是Consumer.**
p = s -> ("".equals(s));
Run Code Online (Sandbox Code Playgroud)
同样,这是一个表达,而不是一个陈述.暂时忽略lambdas,System.out.println("Hello");如果将它包装在括号中,您将看到该行同样无法编译.
*从规格:
如果lambda的主体是一个语句表达式(即,允许独立作为语句的表达式),它与生成void的函数类型兼容; 任何结果都会被丢弃.
lambda表达式与[void-producing]函数类型一致,如果...... lambda body是语句表达式(§14.8)或void兼容块.
Rei*_*ica 11
我认为其他答案通过关注lambda来使解释变得复杂,而在这种情况下它们的行为类似于手动实现方法的行为.这编译:
new Consumer<String>() {
@Override
public void accept(final String s) {
"".equals(s);
}
}
Run Code Online (Sandbox Code Playgroud)
而这不是:
new Consumer<String>() {
@Override
public void accept(final String s) {
true;
}
}
Run Code Online (Sandbox Code Playgroud)
因为"".equals(s)是陈述但true不是.返回void的函数接口的lambda表达式需要一个语句,因此它遵循与方法体相同的规则.
请注意,一般情况下,lambda主体不遵循与方法主体完全相同的规则 - 特别是,如果其主体是表达式的lambda实现了返回值的方法,则它具有隐式return.因此,例如,x -> true它将是一个有效的实现Function<Object, Boolean>,而true;不是一个有效的方法体.但在这种特殊情况下,功能接口和方法体重合.
s -> "".equals(s)
Run Code Online (Sandbox Code Playgroud)
和
s -> true
Run Code Online (Sandbox Code Playgroud)
不要依赖相同的函数描述符.
s -> "".equals(s)可以引用任一String->void或String->boolean函数描述符.
s -> true仅指String->boolean函数描述符.
为什么?
s -> "".equals(s),lambda的主体"".equals(s) 是一个产生一个值的语句.void或 boolean.所以写:
Function<String, Boolean> function = s -> "".equals(s);
Consumer<String> consumer = s -> "".equals(s);
Run Code Online (Sandbox Code Playgroud)
已验证.
将lambda主体分配给Consumer<String>声明的变量时,将使用描述符String->void.
当然,这段代码没有多大意义(你检查相等性而不使用结果),但编译器并不关心.
编写语句时也是如此:myObject.getMyProperty()where getMyProperty()返回一个boolean值,但是你不存储它的结果.
s -> true,lambda的主体:true 是一个单独的表达式.boolean.String->boolean.现在,回到你的代码,不编译.
你想做什么 ?
Consumer<String> p = s -> true;
Run Code Online (Sandbox Code Playgroud)
你不能.您希望为使用函数描述符的变量分配带有函数描述符 Consumer<String>的lambda主体String->void.它不匹配!
| 归档时间: |
|
| 查看次数: |
4579 次 |
| 最近记录: |