Java8 Lambdas和Exceptions

时间:2014-08-27 09:21:21

标签: java lambda java-8

我想知道是否有人可以向我解释以下奇怪之处。我使用的是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,编译器会说

  

未报告的例外X;必须被抓住或宣布被抛出

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

另请参阅here了解可运行的测试代码。

5 个答案:

答案 0 :(得分:81)

这就解决了我的问题:

而不是写

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

我写道:

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

添加显式<BadRequestException>有助于处理这些lambda边缘情况(非常烦人......)

更新:这是为了你不能更新到最新的JDK版本,如果可以的话......

答案 1 :(得分:40)

这看起来像是JDK-8054569的bug,它不会影响Eclipse。

我可以通过将Feed替换为供应商并提取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")));
}

然后进一步删除供应商和lambdas:

abstract <T> void f(T t);

abstract <T, X extends Throwable> T g(X x) throws X;

void bug() {
    f(g(new RuntimeException("foo")));
}

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

我猜想将泛型方法返回类型传递给泛型方法参数导致异常的类型推断失败,因此它假定类型为Throwable并且抱怨此检查的异常类型未被处理。如果您声明bug() throws Throwable或将绑定更改为X extends RuntimeException(因此未选中),则错误消失。

答案 2 :(得分:2)

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

答案 3 :(得分:0)

类似于@keisar,我可以通过指定type参数来解决我的问题(请参见maven-compiler-plugin fails to compile a file that Eclipse has no problem with)。

但是,我发现将异常类设为自己的NotFoundException更为方便(因为我在许多地方都使用Supplier

public class NotFoundException extends RuntimeException
    implements Supplier<NotFoundException> {

    // Rest of the code

    @Override
    public NotFoundException get() {
        return this;
    }

}

然后您可以简单地做到:

// Distribution.rep().get(id) returns a java.util.Optional
Distribution distro = Distribution.rep().get(id).orElseThrow(
    new NotUniqueException("Exception message"));

答案 4 :(得分:0)

如果显式添加<RunTimeException>看起来很丑,那么您可以采用一种解决方法 替换为orElseGet()

.orElseGet(() -> throw new RunTimeException("foo"));