foreach参数与使用者函数接口参数不匹配,但代码仍然可以编译,为什么?

ct3nt3jp  于 2021-06-26  发布在  Java
关注(0)|答案(1)|浏览(367)

我正在学习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<?> 它不是空的,为什么要编译这个代码?

huwehgph

huwehgph1#

lambda表达式的返回类型和目标函数接口类型的函数类型的返回类型必须完全匹配,这并不是真的。java语言规范规定 void 是个特例。
在§15.27.3,它说:
lambda表达式在赋值上下文、调用上下文或转换上下文中与目标类型t兼容(如果t是函数接口类型)(§9.8),并且表达式与从t派生的地面目标类型的函数类型一致。
我们处在一个调用上下文中。 TDoubleConsumer . 由此派生的地面目标类型也是 DoubleConsumer ,其函数类型是采用 double 返回 void .
让我们看看“一致”是什么意思:
如果满足以下所有条件,则lambda表达式与函数类型一致:
[...]
如果假设lambda参数的类型与函数类型的参数类型相同,则:
如果函数类型的结果是 void ,lambda主体是语句表达式(§14.8)或 void -兼容块。
“假定与函数类型的参数类型具有相同的类型”基本上意味着您没有显式地写出 c .
语句表达式只是可以通过添加 ; 最后。任何方法调用都是语句表达式。这就是为什么 submit 调用编译。 5 不是语句表达式(但它是表达式),所以 c -> 5 不编译。
如果你仔细想想,如果你说返回某些东西的方法不应该被分配给函数类型为void返回类型的函数接口,那么你说的是“接受 A 并发出 B “不是一种”的消费者 A ". 然而,他们显然是“产品的消费者” A "! 他们接收一个 A 毕竟。无论某物是否是 A 不取决于他们生产什么。
因此,java设计成允许这样做。

相关问题