英文:
How to throw an exception inside a Lambda?
问题
在lambda内部如何抛出异常?例如在Optional的ifPresentOrElse
中?
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
// 此处的代码需要抛出自定义异常,以便外部可以处理它
// 目前无法直接抛出异常,并且这是一个未处理的异常
}, () -> { response.set(notFound()); }
} catch (CustomException e) {
在抛出异常时执行重要操作();
}
英文:
How do you throw an exception inside a lambda e.g in ifPresentOrElse
of a Optional?
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
// A code inside here needs to throw a custom exception so the outside can handle it
// It can't throw atm, and it is an unhandled exception here
}, () -> { response.set(notFound()); }
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
答案1
得分: 3
虽然你的问题中没有明确提到,但我会假设你打算从 ifPresentOrElse
中抛出一个已检查异常。
首先,你应该尝试理解为什么不能抛出异常。Consumer
接口和 Runnable
一样,只有一个单独的抽象方法,因此它是一个 @FunctionalInterface
。从文档中可以看到:
> 注意,函数式接口的实例可以使用 lambda 表达式、方法引用或构造函数引用来创建。
这是 Consumer
接口的简化版本:
public interface Consumer<T> {
void accept(T t); // <-- 不会抛出异常
}
或者,你仍然可以使用旧的匿名内部类:
Consumer<Object> consumer = new Consumer<>() {
@Override
public void accept(Object o) { // <-- 不会抛出异常
// 处理
}
};
因此,你不能从 accept
方法中抛出已检查异常。这是设计上不可能的。然而,你可以选择以下几种选项:
- 使用自定义的
ThrowingConsumer
和ThrowingOptional
类,它们可以抛出异常(因为你在方法签名中声明了异常),但不建议这样做。 - 将已检查异常包装在
RuntimeException
中,后者无需在方法签名中声明,因此可以抛出。 - 重写代码以不使用 lambda 表达式。
例如,针对最后一点:
Optional<Bar> barOpt = foo.bar(baz);
if(bar.isPresent()) {
Bar bar = barOpt.get();
try {
// 抛出已检查异常的代码
} catch(CustomException e) {
当异常被抛出时的重要操作();
}
} else {
response.set(notFound());
}
英文:
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:
public interface Consumer<T> {
void accept(T t); // <-- NO throws Exception
}
Alternatively, you can still use the old anonymous inner class:
Consumer<Object> consumer = new Consumer<>() {
@Override
public void accept(Object o) { // <-- NO throws Exception
// consume
}
};
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
andThrowingOptional
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:
Optional<Bar> barOpt = foo.bar(baz);
if(bar.isPresent()) {
Bar bar = barOpt.get();
try {
// code that throws checked exception
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
} else {
response.set(notFound());
}
答案2
得分: 0
这个问题的解决方法是使用Project Lombok:
并且,将包装这个函数的方法用SneakyThrows
进行注释,如下所示:
@SneakyThrows
void method() {
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
throw()
}, () -> { response.set(notFound()); }
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
}
英文:
The solution for this is to use Project Lombok:
And have the method wrapping this function annotated with SneakyThrows
, as such:
@SneakyThrows
void method() {
try {
foo.bar(baz).ifPresentOrElse(theBar -> {
throw()
}, () -> { response.set(notFound()); }
} catch(CustomException e) {
somethingImportantWhenExceptionIsThrown();
}
}
答案3
得分: 0
你可以使用Apache Commons Lang3库进行操作。
Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -> {
throw new Exception();
}), () -> {});
英文:
You can do it with apache commons-lang3 library.
Optional.of(obj).ifPresentOrElse(Failable.asConsumer(theBar -> {
throw new Exception();
}), () -> {});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论