与 lambda 和函数式接口一起使用时理解下界的问题

2023-12-27

在学习 Java8 Streams 时,我遇到了以下代码片段:

Predicate<? super String> predicate = s -> s.startsWith("g");

由于通用参数是下限,我认为这不会编译。在我看来,如果一个对象是一个字符串的超类型,那么传入一个对象类型应该会破坏它,因为对象没有startsWith()函数。然而,我很惊讶地发现它没有任何问题地工作。

此外,当我调整谓词以取上限时:

<? extends String>,

它不会编译。

我以为我理解了上限和下限的含义,但显然,我错过了一些东西。任何人都可以帮助解释为什么下限适用于这个 lambda 吗?


Lambda 参数类型是精确的,但不能是? super or ? extends。这涵盖了JLS 15.27.3。 Lambda 表达式的类型 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27。它介绍了地面目标类型概念(基本上是 lambda 类型)。除其他事项外,还指出:

If T是通配符参数化函数接口类型并且 lambda 表达式是隐式类型的,那么基本目标类型是非通配符参数化 (§9.9 https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.9) of T.

强调我的。所以本质上当你写的时候

Predicate<? super String> predicate = s -> s.startsWith("g");

你的 lambda 类型是Predicate<String>。它等同于:

Predicate<? super String> predicate = (Predicate<String>)(s -> s.startsWith("g"));

Or even

Predicate<String> pred = (Predicate<String>)(s -> s.startsWith("g"));
Predicate<? super String> predicate = pred;

考虑到 lambda 类型参数是具体的,之后应用正常的类型转换规则:Predicate<String> is a Predicate<? super String>, or Predicate<? extends String>。所以两者Predicate<? super String> and Predicate<? extends String>应该编译。两者实际上都适用于 javac 8u25、8u45、8u71 以及 ecj 3.11.1。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

与 lambda 和函数式接口一起使用时理解下界的问题 的相关文章

随机推荐