【发布时间】:2015-11-21 19:54:16
【问题描述】:
注意:我发现多个问题指出了 javac 和 Eclipse 编译器之间的差异,但据我所知,他们都讨论了其他问题。
假设我们有这个方法:
public static <T, U> void foo(Supplier<T> a, Function<T, U> b, Consumer<U> c)
{
c.accept(b.apply(a.get()));
}
在编译对此方法的调用时,我发现javac 和 Eclipse Java 编译器之间的行为不同,我不确定两者中哪一个是正确的。
此方法的简单用法可能是:
// variant 1
foo(
() -> Optional.of("foo"),
value -> value.get(),
value -> System.out.println(value));
编译器应该能够使用第一个参数将T 绑定到Optional<String>,使用第二个参数将U 绑定到String。所以这个调用应该是有效的(在我看来)。
使用javac 可以正常编译,但使用 Eclipse 编译失败:
类型不匹配:无法从 void 转换为
将类型参数添加到第一个参数 (() -> Optional.<String> of("foo")) 使其也可以在 Eclipse 中编译。
问题:从规范的角度来看,Eclipse 拒绝此调用是否正确(以及为什么(不))?
现在假设我们要抛出一个自定义(运行时)异常,如果 Optional 为空:
// variant 2
foo(
() -> Optional.of("foo"),
value -> value.orElseThrow(() -> new RuntimeException()),
value -> System.out.println(value));
这被javac 和 Eclipse 编译器拒绝,但错误消息不同:
-
javac: "未报告的异常 X;必须被捕获或声明被抛出" - Eclipse 编译器:“类型不匹配:无法从 void 转换为
”
当我将 type 参数添加到上面的第一个参数时,Eclipse 编译成功,而 javac 仍然失败。当我将<RuntimeException> 作为类型参数添加到第二个参数时,反过来,Eclipse 失败,javac 成功。
问题:同样,编译器拒绝这个调用是否正确?为什么?
在我看来,这两种变体都应该通过使用类型参数在没有额外提示的情况下编译得很好。如果是这样,我将为javac 填写一份错误报告(关于“未报告的异常”)和一份关于Eclipse 编译器的错误报告(关于“类型不匹配”)。但首先我想确保规范与我的观点一致。
使用的版本:
-
javac: 1.8.0_66 - Eclipse JDT:3.11.1.v20151118-1100
编辑:
我为 Eclipse 中的问题填写了 bug 482781。
javac 的问题已报告为JDK-8056983,请参阅Tunakis answer。
【问题讨论】:
-
如果有疑问会怪 Eclipse :) 类型推断非常复杂,整个 lambda 语法仍然很新。 Eclipse 修复了几个错误,但在当前版本中仍然存在一些错误,与此类边缘情况有关。
-
Eclipse Mars ECJ 编译器在泛型扩展方面与最新的 Luna 相比确实存在缺陷。当 javac 和 ECJ 3.10 正确编译时,当 ECJ 3.11 失败甚至陷入无限循环时,我已经偶然发现了至少三种情况。这就是我仍在使用 Luna 的原因。
-
Eclipse 错误已经通过bugs.eclipse.org/470826 修复了 4.6 M1,这也计划用于返回到 mars.2 的端口
-
@TagirValeev 我找不到您针对 ecj 报告的任何错误。您愿意分享您的示例以便改进 Eclipse 吗?您可能还想尝试最近的里程碑版本,因为从 4.5.1 开始就已经修复了类型推断中的大约六个错误。
-
@TagirValeev 最新的 ecj.jar(包含批处理编译器)始终可以在 download.eclipse.org/eclipse/downloads 找到 - 只需选择一个版本,然后在下一页导航到“JDT Core Batch Compiler”,HTH
标签: java java-8 javac eclipse-jdt