我对以下代码感到困惑
class LambdaTest {
public static void main(String[] args) {
Consumer<String> lambda1 = s -> {};
Function<String, String> lambda2 = s -> s;
Consumer<String> lambda3 = LambdaTest::consume; // but s -> s doesn't work!
Function<String, String> lambda4 = LambdaTest::consume;
}
static String consume(String s) { return s;}
}
Run Code Online (Sandbox Code Playgroud)
我原本期望lambda3的赋值失败,因为我的consume方法与Consumer Interface中的accept方法不匹配 - 返回类型不同,String与void.
此外,我一直认为Lambda表达式和方法引用之间存在一对一的关系,但显然并非如我的示例所示.
有人可以向我解释这里发生了什么吗?
Hol*_*ger 19
作为布赖恩戈茨指出,在注释中,为设计决策的基础是允许调整的方法到功能界面,您可以调用该方法以同样的方式,即你可以调用每一个价值回归的方法,而忽略返回值.
说到lambda表达式,事情会变得复杂一些.有两种形式的lambda表达式,(args) -> expression
和(args) -> { statements* }
.
是否与所述第二形式是void
兼容,取决于该问题,通常完全不会尝试返回一个值的所有的代码路径是否,例如() -> { return ""; }
是不void
兼容的,但表达兼容,而() -> {}
或() -> { return; }
是void
兼容.请注意,() -> { for(;;); }
和() -> { throw new RuntimeException(); }
都是,void
兼容和价值兼容,因为它们不正常完成.
return
如果表达式求值为值,则表单与值兼容.但也有表达式,它们同时是陈述.这些表达式可能有副作用,因此可以写为仅用于产生副作用的独立语句,忽略生成的结果.同样,如果表达式也是一个语句,则表单(arg) -> expression
可以(arg) -> expression
兼容.
表单的表达式void
不能s -> s
兼容,因为void
它不是一个声明,即你也不能写s
.另一方面s -> { s; }
可以s -> s.toString()
兼容,因为方法调用是语句.同样,void
可以s -> i++
兼容,因为增量可以用作语句,因此void
也是有效的.当然,s -> { i++; }
必须是一个工作的领域,而不是一个局部变量.
Java语言规范§14.8.表达式语句列出了可用作语句的所有表达式.除了已经提到的方法调用和递增/递减运算,它的名字作业和课程实例创建表达式,所以i
和s -> foo=s
是s -> new WhatEver(s)
兼容了.
作为旁注,表单void
是唯一不兼容的表达形式.
Jus*_*bie 18
consume(String)
方法匹配Consumer<String>
接口,因为它消耗了一个String
- 它返回一个值是无关紧要的事实,因为 - 在这种情况下 - 它被简单地忽略.(因为Consumer
接口根本不期望任何返回值).
它必须是一个设计选择,基本上是一个实用程序:想象有多少方法需要重构或重复以匹配功能接口的需求,Consumer
甚至是非常常见的功能接口Runnable
.(请注意,您可以将任何不使用参数的方法传递Runnable
给Executor
,例如.)
甚至像java.util.List#add(Object)
返回值的方法:boolean
.由于它们返回某些东西(在许多情况下几乎不相关)而无法传递此类方法引用会相当烦人.
归档时间: |
|
查看次数: |
3056 次 |
最近记录: |