我有下面的一段代码,显然不能编译:
jshell> static int counter = 0;
counter ==> 0
jshell> Runnable r = () -> counter;
| Error:
| incompatible types: lambda body is not compatible with a void functional interface
| (consider using a block lambda body, or use a statement expression instead)
| Runnable r = () -> counter;
|
这是可以理解的,因为Runnable
的run
的签名是void run()
。现在,如果我有下面的lambda,这将编译得很好:
jshell> static int counter = 0;
counter ==> 0
jshell> Runnable r = () -> counter++;
r ==> $Lambda$23/0x0000000800c0b260@3941a79c
既然知道counter++
仍然会返回整数,为什么还要编译这段代码呢?
另外,更让人困惑的是,这段代码也可以编译:
jshell> Supplier<Integer> f = () -> counter++;
f ==> $Lambda$22/0x0000000800c0a410@12edcd21
我尝试使用Java17的jshell编译上面的代码。
2条答案
按热度按时间8zzbczxx1#
在
Runnable
中,忽略返回值;最主要的部分(为什么要编译)是因为其中有一条语句。它确实返回一个值,所以它也是一个
Supplier
,它也操作counter
(作为一个副作用),但这对实现函数接口无关紧要。oiopk7p52#
(扩展评论,借用其他答案和评论)
如果您将 consider using a block lambda body 解释为“consider what would happened if you used a block lambda body”(考虑如果您使用了块lambda body会发生什么),那么错误消息本身就提供了一些指导。
当你编写一个无块lambda函数
arguments -> something
时,Java仍然会从两个实际的块中选择一个:1.
和(如其他答案和注解所指出)在这种情况下
something;
必须是有效语句1.
,其中
something
必须是有效表达式,提供要返回的结果。选择是显式的,您可以在指定lambda本身的类型时亲自进行选择。
因此,当你编写
Runnable
时,它只有一个void run()
方法,Java会尝试为你创建它:1.
这不会起作用,因为
counter;
在Java中不存在1.这是行不通的,因为
void
方法不能return
一个数字。然而,后一个方法可以与
Supplier<Integer>
一起使用,Supplier<Integer>
只有一个Integer get()
方法:1.
此方法可以存在(使用自动
int
-〉Integer
装箱)。当你有
counter++
时,两者都可以存在,(1.)对于Runnable
,(2.)对于Supplier<Integer>
:1.
递增
counter
,不返回任何值1.
递增
counter
并返回递增前的值。