为何将含counter++的Lambda赋值给Runnable可正常编译?
关于Java Lambda与Runnable/Supplier的编译疑问
问题场景
场景1:编译失败的代码
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,而lambda直接返回了counter这个int值,类型不匹配,这点容易理解。
场景2:编译成功的Runnable代码
jshell> static int counter = 0; counter ==> 0 jshell> Runnable r = () -> counter++; r ==> $Lambda$23/0x0000000800c0b260@3941a79c
这里counter++会返回自增前的int值,但这段代码却能正常编译。
场景3:编译成功的Supplier代码
jshell> Supplier<Integer> f = () -> counter++; f ==> $Lambda$22/0x0000000800c0a410@12edcd21
这段代码同样使用counter++,赋值给要求返回Integer的Supplier<Integer>,也能正常编译。
原因解释
这是Java Lambda表达式的语法规则决定的:
- 对于返回值为void的函数式接口(比如
Runnable),lambda体可以是一个语句表达式(Statement Expression)。counter++属于语句表达式——它既是一个表达式(有返回值),也可以作为一条独立语句执行。Java允许在void型的lambda中使用这类表达式,此时会自动忽略它的返回值,只执行表达式对应的操作。 - 而
counter只是一个普通表达式,不是语句表达式,不能直接作为void型lambda的主体,必须用代码块包裹(比如() -> { counter; }),但这样写其实也没意义,因为只是读取变量不做操作。 - 对于有返回值要求的函数式接口(比如
Supplier<Integer>),lambda体如果是表达式,就会把表达式的返回值作为接口方法的返回值。counter++的返回值是int,会自动装箱为Integer,符合Supplier<Integer>的返回要求,所以能正常编译。
简单总结:counter是纯表达式,不能直接用于void型lambda;counter++是语句表达式,既可以在void型lambda中忽略返回值执行,也可以在有返回值要求的lambda中返回其结果。
内容的提问来源于stack exchange,提问作者JavaOCPLearner
相关产品推荐
相关产品推荐

