Joh*_*uhn 6 java lambda javac method-reference
当我尝试编译这段代码时
import java.util.Optional;
public class GenericTest {
public static void main(String[] args) {
Optional.empty().map(o -> getStringClass(o)).orElse(String.class);
}
static Class<?> getStringClass(Object arg) {
return String.class;
}
}
Run Code Online (Sandbox Code Playgroud)
javac将失败,并显示以下错误:
GenericTest.java:6:错误:类别Optional中的方法orElse无法应用于给定类型;
Optional.empty()。map(o-> getStringClass(o))。orElse(String.class);
^
必需:Class <CAP#1>
找到:类<String>
原因:参数不匹配;Class <String>无法转换为Class <CAP#1>
其中T是类型变量:
T扩展了在Optional类中声明的Object
CAP#1是新鲜的类型变量:
CAP#1扩展了对象的捕获范围
1个错误
但是,如果我改用方法引用,则javac会很好地编译代码:
import java.util.Optional;
public class GenericTest {
public static void main(String[] args) {
Optional.empty().map(GenericTest::getStringClass).orElse(String.class);
}
static Class<?> getStringClass(Object arg) {
return String.class;
}
}
Run Code Online (Sandbox Code Playgroud)
如果使用方法引用或lambda表达式,为什么会有区别?
根据我的理解,方法引用和lambda都具有type Function<Object,Class<?>>,所以在这里我看不到区别。
Eclipse Java编译器(ecj)不会同时编译两个版本。
这是编译器类型推断系统的一个已知限制,它不适用于第一个代码片段中的链式方法调用。
可能的解决方法?使用显式类型化的 lambda 表达式:
Optional.empty()
.map((Function<Object, Class<?>>) o -> getStringClass(o))
.orElse(String.class);
Run Code Online (Sandbox Code Playgroud)
或确切的方法参考(正如您已经尝试过的那样):
Optional.empty().map(GenericTest::getStringClass).orElse(String.class);
Run Code Online (Sandbox Code Playgroud)
或添加类型见证:
Optional.empty().<Class<?>>map(o -> getStringClass(o)).orElse(String.class);
Run Code Online (Sandbox Code Playgroud)
具有类似问题的相关帖子。
方法链再次出现。您可以在此处阅读为什么此功能的设计者发现实现起来很复杂(这与 lambda/方法引用是多表达式- 它们的类型依赖于上下文这一事实有关)。这样的功能将需要编译器承担一些额外的负担 - 虽然您的示例将是一个相当琐碎的示例,但javac必须关心的不仅仅是琐碎的事情;因此,即使在 java-12 中,这也尚未实现。
在我看来,最简单的解决方案是不链接,因为这与方法链接有关(在您的情况下这是可能的):
Optional<Class<?>> first = Optional.empty().map(o -> getStringClass(o));
Class<?> second = first.orElse(String.class);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
169 次 |
| 最近记录: |