【问题标题】:Java8 Lambdas and ExceptionsJava8 Lambda 和异常
【发布时间】:2014-10-20 19:33:40
【问题描述】:

我想知道是否有人可以向我解释以下奇怪之处。我正在使用 Java 8 更新 11。

给定这个方法

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

如果我首先构造一个函数对象,并将其传递给上面的方法,事情就会编译。

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 以获取可运行的测试代码。

【问题讨论】:

  • 听起来像是另一个类型推断错误。由于 Eclipse 使用自己的,因此请务必包含有关您收到此错误的 编译器 的详细信息。
  • 请注意,如果您使用匿名类,也会发生同样的事情,因此这不是 lambda 问题。
  • 顺便说一句:Eclipse 编译它就好了,使用o.&lt;RuntimeException&gt;orElseThrow(()... 解决了这个问题,但是,这不是必需的。 (我认为前段时间在另一个stackoverflow问题中报告了类似的问题,但我现在没有找到它......)
  • "mvn -e" 会很有帮助。

标签: java lambda java-8


【解决方案1】:

这就是为我解决问题的方法:

而不是写

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

我写道:

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

添加显式 &lt;BadRequestException&gt; 有助于解决这些 lambda 边缘情况(这很烦人......)

更新:这是为了防止您无法更新到最新的 JDK 版本,如果可以的话,您应该...

【讨论】:

  • 我使用的是最新版本的 Java,但仍然出现错误。 .getOrElseThrow(throwable 帮了我。谢谢。
  • 这对我有帮助,谢谢,因为我没有这台机器,所以无法升级
  • 我在 1.8.0_144,仍然必须使用您的解决方案。它有帮助
  • Oracle的1.8.0_171也坏了。
  • 1.8.0_181 也需要显式转换。
【解决方案2】:

这看起来像是一个错误JDK-8054569 的情况,它不会影响 Eclipse。

我能够通过将 Function 替换为 Supplier 并提取 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 下可以正常工作。

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

【讨论】:

  • 从 1.8.0_45 更新到 1.8.0_92,它解决了我的问题。谢谢
【解决方案3】:

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

【讨论】:

  • 你确定吗?我在 _101 中仍然存在此错误,其他人在 _171 中报告此错误
【解决方案4】:

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

但是,我发现让我的异常类成为自己的Supplier 更方便(因为我在很多地方都使用了NotFoundException

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"));

【讨论】:

    【解决方案5】:

    如果显式添加 &lt;RunTimeException&gt; 看起来很难看,那么作为一种解决方法,您可以 替换为orElseGet()

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

    【讨论】:

    • 我不认为你可以像那样内联抛出异常...... throw 语句需要在一个块中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    • 2020-11-08
    • 2020-09-23
    相关资源
    最近更新 更多