如何在 Lambda 内部抛出异常?

huangapple go评论98阅读模式
英文:

How to throw an exception inside a Lambda?

问题

在lambda内部如何抛出异常?例如在Optional的ifPresentOrElse中?

  1. try {
  2. foo.bar(baz).ifPresentOrElse(theBar -> {
  3. // 此处的代码需要抛出自定义异常,以便外部可以处理它
  4. // 目前无法直接抛出异常,并且这是一个未处理的异常
  5. }, () -> { response.set(notFound()); }
  6. } catch (CustomException e) {
  7. 在抛出异常时执行重要操作();
  8. }
英文:

How do you throw an exception inside a lambda e.g in ifPresentOrElse of a Optional?

  1. try {
  2. foo.bar(baz).ifPresentOrElse(theBar -> {
  3. // A code inside here needs to throw a custom exception so the outside can handle it
  4. // It can't throw atm, and it is an unhandled exception here
  5. }, () -> { response.set(notFound()); }
  6. } catch(CustomException e) {
  7. somethingImportantWhenExceptionIsThrown();
  8. }

答案1

得分: 3

虽然你的问题中没有明确提到,但我会假设你打算从 ifPresentOrElse 中抛出一个已检查异常。

首先,你应该尝试理解为什么不能抛出异常。Consumer 接口和 Runnable 一样,只有一个单独的抽象方法,因此它是一个 @FunctionalInterface。从文档中可以看到:

> 注意,函数式接口的实例可以使用 lambda 表达式、方法引用或构造函数引用来创建。

这是 Consumer 接口的简化版本:

  1. public interface Consumer<T> {
  2. void accept(T t); // &lt;-- 不会抛出异常
  3. }

或者,你仍然可以使用旧的匿名内部类:

  1. Consumer<Object> consumer = new Consumer<>() {
  2. @Override
  3. public void accept(Object o) { // &lt;-- 不会抛出异常
  4. // 处理
  5. }
  6. };

因此,你不能accept 方法中抛出已检查异常。这是设计上不可能的。然而,你可以选择以下几种选项:

  • 使用自定义的 ThrowingConsumerThrowingOptional 类,它们可以抛出异常(因为你在方法签名中声明了异常),但不建议这样做。
  • 将已检查异常包装在 RuntimeException 中,后者无需在方法签名中声明,因此可以抛出。
  • 重写代码以不使用 lambda 表达式。

例如,针对最后一点:

  1. Optional<Bar> barOpt = foo.bar(baz);
  2. if(bar.isPresent()) {
  3. Bar bar = barOpt.get();
  4. try {
  5. // 抛出已检查异常的代码
  6. } catch(CustomException e) {
  7. 当异常被抛出时的重要操作();
  8. }
  9. } else {
  10. response.set(notFound());
  11. }
英文:

Altough not explicitly mentioned in your question, i am going to assume that you intent to throw a checked exception from ifPresentOrElse.

First, you should try to understand why you cannot throw an exception. The Consumer interface has, as Runnable, only a single abstract method, which makes it a @FunctionalInterface. From the documentation:

> Note that instances of functional interfaces can be created with
> lambda expressions, method references, or constructor references.

This is a reduced version of the Consumer interface:

  1. public interface Consumer&lt;T&gt; {
  2. void accept(T t); // &lt;-- NO throws Exception
  3. }

Alternatively, you can still use the old anonymous inner class:

  1. Consumer&lt;Object&gt; consumer = new Consumer&lt;&gt;() {
  2. @Override
  3. public void accept(Object o) { // &lt;-- NO throws Exception
  4. // consume
  5. }
  6. };

Therefore, you cannot throw a checked exception from the accept method. It is not possible by design. You can, however, chose one of the following options:

  • Use a custom ThrowingConsumer and ThrowingOptional class, which can throw exceptions (since you declare them in their method signatures), not recommended.
  • Wrap the checked exception in a RuntimeException, which does not need to be declared in the method signature, and can therefore be thrown.
  • Rewrite your code to not use the lambda expression.

Example, for the last point:

  1. Optional&lt;Bar&gt; barOpt = foo.bar(baz);
  2. if(bar.isPresent()) {
  3. Bar bar = barOpt.get();
  4. try {
  5. // code that throws checked exception
  6. } catch(CustomException e) {
  7. somethingImportantWhenExceptionIsThrown();
  8. }
  9. } else {
  10. response.set(notFound());
  11. }

答案2

得分: 0

这个问题的解决方法是使用Project Lombok

并且,将包装这个函数的方法用SneakyThrows进行注释,如下所示:

  1. @SneakyThrows
  2. void method() {
  3. try {
  4. foo.bar(baz).ifPresentOrElse(theBar -> {
  5. throw()
  6. }, () -> { response.set(notFound()); }
  7. } catch(CustomException e) {
  8. somethingImportantWhenExceptionIsThrown();
  9. }
  10. }
英文:

The solution for this is to use Project Lombok:

And have the method wrapping this function annotated with SneakyThrows, as such:

  1. @SneakyThrows
  2. void method() {
  3. try {
  4. foo.bar(baz).ifPresentOrElse(theBar -&gt; {
  5. throw()
  6. }, () -&gt; { response.set(notFound()); }
  7. } catch(CustomException e) {
  8. somethingImportantWhenExceptionIsThrown();
  9. }
  10. }

答案3

得分: 0

你可以使用Apache Commons Lang3库进行操作。

https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html

  1. Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -> {
  2. throw new Exception();
  3. }), () -> {});
英文:

You can do it with apache commons-lang3 library.

https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html

  1. Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -&gt; {
  2. throw new Exception();
  3. }), () -&gt; {});

huangapple
  • 本文由 发表于 2020年10月21日 02:06:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/64451002.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定