我正在学习ocp考试,我注意到下面的一段代码,在doublestream上调用的foreach方法的参数必须与doubleconsumer函数接口的参数匹配,但是lambda与所需的类型不匹配,为什么它仍然编译?
DoubleStream.of(3.14159, 2.71828)
.forEach(c -> service.submit(
() -> System.out.println(10*c)
));
doubleconsumer(接受double类型的参数,返回类型为void),但是这个foreach的返回类型为 Future<?>
哪里?表示可运行lambda的返回类型,它是void,future-这不是void。我这么说是因为service.submit(…)的返回类型是 Future<?>
它不是空的,为什么要编译这个代码?
1条答案
按热度按时间huwehgph1#
lambda表达式的返回类型和目标函数接口类型的函数类型的返回类型必须完全匹配,这并不是真的。java语言规范规定
void
是个特例。在§15.27.3,它说:
lambda表达式在赋值上下文、调用上下文或转换上下文中与目标类型t兼容(如果t是函数接口类型)(§9.8),并且表达式与从t派生的地面目标类型的函数类型一致。
我们处在一个调用上下文中。
T
是DoubleConsumer
. 由此派生的地面目标类型也是DoubleConsumer
,其函数类型是采用double
返回void
.让我们看看“一致”是什么意思:
如果满足以下所有条件,则lambda表达式与函数类型一致:
[...]
如果假设lambda参数的类型与函数类型的参数类型相同,则:
如果函数类型的结果是
void
,lambda主体是语句表达式(§14.8)或void
-兼容块。“假定与函数类型的参数类型具有相同的类型”基本上意味着您没有显式地写出
c
.语句表达式只是可以通过添加
;
最后。任何方法调用都是语句表达式。这就是为什么submit
调用编译。5
不是语句表达式(但它是表达式),所以c -> 5
不编译。如果你仔细想想,如果你说返回某些东西的方法不应该被分配给函数类型为void返回类型的函数接口,那么你说的是“接受
A
并发出B
“不是一种”的消费者A
". 然而,他们显然是“产品的消费者”A
"! 他们接收一个A
毕竟。无论某物是否是A
不取决于他们生产什么。因此,java设计成允许这样做。