假设我们有这个方法:
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 转换为 <unknown>
在第一个参数 (() -> 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转换为<unknown>"
当我像上面那样给第一个参数添加类型参数时,Eclipse成功编译,而javac
仍然失败。当我将<RuntimeException>
作为类型参数添加到第二个参数时,情况正好相反,Eclipse失败了,而javac
成功了。
问题:编译器拒绝这个调用是正确的吗?为什么?
在我看来,两种变体都应该通过使用类型参数而无需其他提示而编译成功。如果是这样,我将为javac
(关于“未报告的异常”)和Eclipse编译器(关于“类型不匹配”)填写一个bug报告。但是首先,我想确定规范是否分享我的观点。
所用版本:
javac
:1.8.0_66- Eclipse JDT:3.11.1.v20151118-1100
编辑:
我为Eclipse中的问题填写了bug 482781。
javac
的问题已经报告为JDK-8056983,请参见Tunakis answer。