Ram*_*nSB 3 java concurrency lambda return-type executor
我正在为 OCP 考试而学习,我注意到以下代码片段,其中在 DoubleStream 上调用的 forEach 方法的参数必须与 DoubleConsumer 函数接口的参数匹配,但是 lambda 与所需的类型不匹配,为什么它仍然编译?
DoubleStream.of(3.14159, 2.71828)
.forEach(c -> service.submit(
() -> System.out.println(10*c)
));
Run Code Online (Sandbox Code Playgroud)
DoubleConsumer(接受 Double 类型的参数并返回 void 类型),但是这个 forEach 的返回类型为Future<?>where ?表示 Runnable lambda 的返回类型,它是 void,Future - 这不是 void。我这么说是因为 service.submit(...) 的返回类型Future<?>不是 void,为什么这段代码会编译?
Lambda 表达式的返回类型和目标函数接口类型的函数类型的返回类型必须为 完全匹配。Java 语言规范指定这void是一种特殊情况。
在 §15.27.3 中,它说:
如果 T 是函数接口类型(第 9.8 节)并且表达式与从 T 派生的基础目标类型的函数类型一致,则 lambda 表达式在具有目标类型 T 的赋值上下文、调用上下文或转换上下文中兼容。
我们在这里处于调用上下文中。T是DoubleConsumer。从它派生的地面目标类型也是DoubleConsumer,它的功能类型是一个方法double并返回的方法void。
让我们看看“一致”是什么意思:
如果以下所有条件都为真,则 lambda 表达式与函数类型一致:
- [...]
- 如果假定 lambda 参数具有与函数类型的参数类型相同的类型,则:
- 如果函数类型的结果是
void,则 lambda 主体是语句表达式(第14.8 节)或void兼容块。
“假设与函数类型的参数类型具有相同的类型”基本上意味着您没有明确写出的类型 c.
语句表达式只是一个表达式,可以通过添加一个语句变成语句 ;在末尾。任何方法调用都是一个语句表达式。这就是submit调用编译的原因。
5 不是语句表达式(但它是一个表达式),所以 c -> 5不编译。
如果你考虑一下,通过说返回某些东西的方法不应该分配给函数类型具有 void 返回类型的函数接口,你是在说“接受 aA并给出 a 的函数B”不是一种“消费者”的A“。然而,他们显然是“消费者A”!A毕竟他们接受了。某物是否为消费者A并不取决于他们生产什么。
因此,Java 旨在允许这样做。
| 归档时间: |
|
| 查看次数: |
56 次 |
| 最近记录: |