【问题标题】:forEach parameter does not match Consumer functional interface parameters but code still compiles, why?forEach 参数与 Consumer 功能接口参数不匹配但代码仍然可以编译,为什么?
【发布时间】:2021-01-09 05:47:22
【问题描述】:

我正在为 OCP 考试学习,我注意到以下 sn-p 代码,其中在 DoubleStream 上调用的 forEach 方法的参数必须与 DoubleConsumer 功能接口的参数匹配,但是 lambda 与所需的类型不匹配,为什么还能编译?

  DoubleStream.of(3.14159, 2.71828)
    .forEach(c -> service.submit(
      () -> System.out.println(10*c)
    ));

DoubleConsumer(接受 Double 类型的参数,返回类型为 void),但是这个 forEach 的返回类型为 Future<?> 哪里?表示 Runnable lambda 的返回类型,它是 void,Future - 这不是 void。我这么说是因为 service.submit(...) 的返回类型是 Future<?> 它不是 void,为什么这段代码会编译?

【问题讨论】:

  • 如果预期的返回类型是void,这意味着不需要结果。 Java 也允许在此处返回任何其他内容。它会自动丢弃它。这是一种“无损”且安全的转换。
  • 和独立语句service.submit(...);一样,不给变量赋值,返回值被丢弃。如果您可以在普通语句中执行 discard,为什么不能在将 lambda 表达式映射到函数方法时呢?
  • @Andreas 不,我不相信,返回类型不会被丢弃:考虑以下 lambda: () -> 5。值 5 被视为返回类型,在在上述情况下, service.submit 的返回类型被认为是 Future 的返回类型
  • 消费者只需要满足FunctionConsumer都可以做到的“对流元素做某事”的约定。
  • @RamanSB 与您不能只写5; 一样,因为表达式不是语句,() -> 5void 函数方法无效。然而,() -> String.valueOf(5) 是,即使它返回一个值,因为带有返回值的方法调用可以用作表达式中的语句 and证明: Runnable x = () -> String.valueOf(5); 编译并执行得很好。 valueOf() 的返回值被丢弃,就像String.valueOf(5); 这样的独立语句一样。可能会忽略方法返回值这一事实对于 lambdas 来说并不新鲜。

标签: java lambda concurrency return-type executor


【解决方案1】:

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

§15.27.3 中,它说:

如果 T 是函数式接口类型(第 9.8 节)并且表达式与派生的基本目标类型的函数类型一致,则 lambda 表达式在赋值上下文、调用上下文或转换上下文中与目标类型 T 兼容来自T。

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

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

如果满足以下所有条件,则 lambda 表达式与函数类型一致:

  • [...]
  • 如果假定 lambda 参数的类型与函数类型的参数类型相同,则:
    • 如果函数类型的结果是 void,则 lambda 主体是语句表达式 (§14.8) 或 void 兼容块。

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

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

5 不是语句表达式(但它是表达式),所以c -> 5 无法编译。

如果您考虑一下,如果说返回 something 的方法不应该分配给函数类型具有 void 返回类型的函数式接口,那么您是在说“采用 @987654336 的函数@ 并给出一个B”不是一种“A”的消费者。但是,他们显然A 的消费者”!毕竟他们接受了A。某物是否是A 的消费者并不取决于它们生产什么

因此,Java 旨在实现这一点。

【讨论】:

    猜你喜欢
    • 2021-04-19
    • 2018-03-05
    • 2021-10-17
    • 2017-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-19
    相关资源
    最近更新 更多