Java8的Lambda和例外

我想知道是否有人可以向我解释下面这个怪事。 我正在使用Java 8更新11。

给定这种方法

private <F,T> T runFun(Function<Optional<F>, T> fun, Optional<F> opt) { return fun.apply(opt) ; } 

如果我首先构造一个函数Object,并将其传入上面的方法,则编译。

 private void doesCompile() { Function<Optional<String>, String> fun = o -> o.orElseThrow(() -> new RuntimeException("nah")); runFun(fun, Optional.of("foo")); } 

但是,如果我把这个函数作为一个lambda函数进行内联,编译器说

未报告的exceptionX; 必须被逮捕或宣布被抛出

 private void doesNotCompile () { runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo")); } 

更新 :原来的错误消息被maven缩写。 如果直接用javac编译,错误是:

 error: unreported exception X; must be caught or declared to be thrown runFun(o -> o.orElseThrow(() -> new RuntimeException("nah")), Optional.of("foo")); ^ where X,T are type-variables: X extends Throwable declared in method <X>orElseThrow(Supplier<? extends X>) T extends Object declared in class Optional 

另请参阅可运行的testing代码。

这看起来像是JDK-8054569错误,它不影响Eclipse。

我能够通过replace供应商函数并提取orElseThrow方法来缩小范围:

 abstract <T> void f(Supplier<T> s); abstract <T, X extends Throwable> T g(Supplier<? extends X> x) throws X; void bug() { f(() -> g(() -> new RuntimeException("foo"))); } 

然后进一步删除供应商和lambda完全:

 abstract <T> void f(T t); abstract <T, X extends Throwable> T g(X x) throws X; void bug() { f(g(new RuntimeException("foo"))); } 

这实际上比臭虫报告中的一个更清晰的例子。 如果编译为Java 8,则显示相同的错误,但使用-source 1.7可以正常工作。

我想有关将generics方法返回types传递给generics方法参数的事情导致exception的types推断失败,所以它假定types是Throwable,并且抱怨说这个检查的exceptiontypes没有被处理。 如果你声明bug() throws Throwable或更改绑定到X extends RuntimeException (所以它没有选中),错误消失。

这是为我解决了这个问题:

而不是写作

 optional.map(this::mappingFunction).orElseThrow(() -> new BadRequestException("bla bla")); 

我写了:

 optional.map(this::mappingFunction).<BadRequestException>orElseThrow(() -> new BadRequestException("bla bla")); 

添加显式的<BadRequestException>有助于这些lambda边缘情况(这是非常恼人的…)

更新:这是万一你不能更新到最新的JDK版本,如果你可以你应该…

如果您正在尝试编译其他人的项目,请尝试升级到1.8.0_92