Java8的Lambda和例外
我想知道是否有人可以向我解释下面这个怪事。 我正在使用Java 8更新11。
给定这种方法
private T runFun(Function, T> fun, Optional opt) { return fun.apply(opt) ; }
如果我首先构造一个函数Object,并将其传入上面的方法,则编译。
private void doesCompile() { Function, 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 orElseThrow(Supplier extends X>) T extends Object declared in class Optional
另请参阅可运行的testing代码。
这看起来像是JDK-8054569错误,它不影响Eclipse。
我能够通过replace供应商函数并提取orElseThrow方法来缩小范围:
abstract void f(Supplier s); abstract T g(Supplier extends X> x) throws X; void bug() { f(() -> g(() -> new RuntimeException("foo"))); }
然后进一步删除供应商和lambda完全:
abstract void f(T t); abstract 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).orElseThrow(() -> new BadRequestException("bla bla"));
添加显式的有助于这些lambda边缘情况(这是非常恼人的…)
更新:这是万一你不能更新到最新的JDK版本,如果你可以你应该…
如果您正在尝试编译其他人的项目,请尝试升级到1.8.0_92