【问题标题】:Generics and lambdas - different behavior in javac and Eclipse compiler泛型和 lambda - javac 和 Eclipse 编译器中的不同行为
【发布时间】: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&lt;String&gt;,使用第二个参数将U 绑定到String。所以这个调用应该是有效的(在我看来)。

使用javac 可以正常编译,但使用 Eclipse 编译失败:

类型不匹配:无法从 void 转换为

将类型参数添加到第一个参数 (() -&gt; Optional.&lt;String&gt; 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 仍然失败。当我将&lt;RuntimeException&gt; 作为类型参数添加到第二个参数时,反过来,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


【解决方案1】:

是的,你在各个方面都是对的。老实说,我无法链接到 JLS 的特定行:类型推断is a whole chapter

免责声明:我使用 Eclipse Mars 4.5.1 和 JDK 1.8.0_60 进行了测试。


变体 1 应该可以编译,而 Eclipse 在这里有一个错误。我在他们的 Bugzilla 中找不到与此相关的任何内容,因此您可以继续归档。如果您将示例简化为以下内容,您可以向自己保证它应该可以编译:

public static <T> void foo(Supplier<T> a) {
    a.get();
}

foo(() -> Optional.of("foo"));

这与 Eclipse 和 javac 都可以正常编译。添加参数不会(应该)在编译期间更改为T 推断的类型。


变体 2 不能针对 javac 进行编译,这确实是一个错误,正如 JDK-8056983 中所报告的那样。编译器应该能够推断出XRuntimeException。至于为什么 Eclipse 仍然无法编译这个,我再次在他们的 Bugzilla 中找不到任何东西,所以请随时报告!

【讨论】:

    猜你喜欢
    • 2011-02-20
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多