在 Java 1.8 中,以下lambda表达式符合Runnable
和Callable
功能接口:
() -> {
throw new RuntimeException("FIXME");
}
但是,如果我使用单参数方法将其提交给ExecutorService
并忽略返回值(即没有可用的类型推断信息),则在编译时选择ExecutorService#submit(Callable)
,除非我明确地将我的lambda转换为Runnable
。
如果Runnable
和Callable
不共享任何公共层次结构且最具体的类型规则没有',编译器如何在上述情况下在重载方法之间进行选择适用于此?
答案 0 :(得分:7)
我相信这是因为Callable
声明了返回类型,Runnable
没有。
从JLS部分15.12.2.5中,选择具有最特定类型的重载,如果有一个明确最具体的那样。这就是它对大多数特定功能接口类型的说法:
如果T不是S的子类型且下列之一为真,则功能接口类型S比表达式e的功能接口类型T更具体(其中U1 ... Uk和R1是参数类型和返回类型为S的捕获函数类型,V1 ... Vk和R2是T)函数类型的参数类型和返回类型:
如果e是显式类型的lambda表达式(第15.27.1节),则以下之一为真:
- R2无效......
T
为Runnable
,S
为Callable
,Callable
更具体,因为其返回类型不为空,因此Callable
为选择
方法重载解析非常复杂,所以可能有一点我错过了,但我认为这就是为什么它选择Callable
答案 1 :(得分:4)
虽然@thecoop的答案是正确的,但值得一提的是lambda机制的另一个方面。
带有块体的Lambda分为两类:void-compatible and value-compatible。
问题中的lambda都是,因为它无法正常完成(由于无条件的异常抛出),并且那里的所有return
语句都是无值的并且返回一个值,看得出来就像那里一样根本没有return
声明。
然而,大多数lambdas都是其中之一。如果lambda只有void-compatible
,则lambda只与Runnable
兼容。
稍微违反直觉(但在逻辑上正确)的是,即使问题中的lambda永远不会返回一个值,它也会被归类为"总是在sa {{1}时返回一个值}"