有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在学习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<?>where?表示可运行lambda的返回类型,它是void,Future-这不是void。我这么说是因为退货服务的类型。提交(…)它不是空的,为什么要编译这段代码


共 (1) 个答案

  1. # 1 楼答案

    lambda表达式的返回类型和目标函数接口类型的函数类型的返回类型必须完全匹配,这并不是真的。Java语言规范规定void是一种特殊情况

    §15.27.3中,它说:

    A lambda expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.

    我们处在一个调用上下文中TDoubleConsumer。从它派生的地面目标类型也是DoubleConsumer,其函数类型是一个方法,它接受double并返回void

    让我们看看“一致”是什么意思:

    A lambda expression is congruent with a function type if all of the following are true:

    • [...]
    • If the lambda parameters are assumed to have the same types as the function type's parameter types, then:
      • If the function type's result is void, the lambda body is either a statement expression (§14.8) or a void-compatible block.

    “假定具有与函数类型的参数类型相同的类型”基本上意味着没有显式写出c的类型

    语句表达式只是一个表达式,可以通过在末尾添加;来生成语句。任何方法调用都是一个语句表达式。这就是submit调用编译的原因

    5不是语句表达式(但它是一个表达式),因此c -> 5不编译

    如果你想一想,如果你说返回某物的方法不应该被分配给函数类型为void返回类型的函数接口,那么你是说“接受A并给出B的函数”不是一种A的消费者。然而,他们显然是A的消费者!毕竟,他们接受了A。某物是否是A的消费者并不取决于它们生产的

    因此,Java就是为了实现这一点而设计的