英文:
How to throw exception when Try.of() fails?
问题
我想要抛出继承自Exception
的异常,如果Try.ofCallable()
失败。
我有一个类型为的可调用对象:
final Callable<MyResponse> decoratedCallable =
circuitBreakerService.getDecoratedMethod(
myArg1,
() -> myFunction(myArg1, myArg2, myArg3)
);
我正在尝试类似这样的操作:
Try.ofCallable(decoratedCallable).onFailure(throwable -> {
if (throwable instanceof CallNotPermittedException) {
throw new MyRuntimeExceptionA("msg1", throwable);
} else {
throw new MyRuntimeExceptionB("msg2", throwable);
}
});
如果MyRuntimeExceptionA
和MyRuntimeExceptionB
都继承自RuntimeException
,那么这将有效(包装上述两个语句的函数会抛出正确的异常MyRuntimeExceptionA
和MyRuntimeExceptionB
),但如果它们继承自Exception
,那么我无法从主函数中抛出它们。IDE要求将它们包装在try/catch中,但我不想这样做。
英文:
I want to throw Exceptions that are extended from Exception
if Try.ofCallable()
fails.
I have a callable of the type:
final Callable<MyResponse> decoratedCallable =
circuitBreakerService.getDecoratedMethod(
myArg1,
() -> myFunction(myArg1, myArg2, myArg3)
);
I am trying something like this:
Try.ofCallable(decoratedCallable).onFailure(throwable -> {
if (throwable instanceof CallNotPermittedException) {
throw new MyRuntimeExceptionA("msg1", throwable);
} else {
throw new MyRuntimeExceptionB("msg2", throwable);
}
});
This works (the function that wraps the above two statements throws the correct exception MyRuntimeExceptionA and MyRuntimeExceptionB) if both MyRuntimeExceptionA
and MyRuntimeExceptionB
extend RuntimeException
, but not if they extend Exception
.
If they extend Exception
then I am not able to throw them from the main function.
The IDE asks to wrap them in try/catch - which I don't want.
答案1
得分: 5
您有两个选项。您可以在尝试使用以下代码解包Try
并获取值时引发异常:
Try.ofCallable(decoratedCallable)
.getOrElseThrow(throwable -> {
if (throwable instanceof CallNotPermittedException) {
return new MyExceptionA("msg1", throwable);
} else {
return new MyExceptionB("msg2", throwable);
}
})
或者,将错误映射代码移到解包之前,使用类似的代码:
Try.ofCallable(decoratedCallable)
.mapFailure(
Case(
$(instanceOf(CallNotPermittedException.class)),
throwable -> new MyExceptionA("msg1", throwable)
),
Case($(), throwable -> new MyExceptionB("msg2", throwable))
)
.get()
这两种解决方案只有在解包时才会引发异常,因此如果要早期引发异常,您必须提前解包。
否则,如果您正在使用Try
,我建议采纳其他人在评论中提到的建议,不要引发异常。使用Try
的整个目的是使用总函数而不是可以引发异常的部分函数。
英文:
You have two options. You can throw when you try to unwrap the Try
by getting the value with the following code:
Try.ofCallable(decoratedCallable)
.getOrElseThrow(throwable -> {
if (throwable instanceof CallNotPermittedException) {
return new MyExceptionA("msg1", throwable);
} else {
return new MyExceptionB("msg2", throwable);
}
})
or move out the error mapping code to before unwrapping with a similar code:
Try.ofCallable(decoratedCallable)
.mapFailure(
Case(
$(instanceOf(CallNotPermittedException.class)),
throwable -> new MyExceptionA("msg1", throwable)
),
Case($(), throwable -> new MyExceptionB("msg2", throwable))
)
.get()
Both solutions will only throw when unrwapping, so if you want to throw early, you will have to unwrap early.
Otherwise, I would take the advice others posted in comments not to throw exceptions if you are using Try
. The whole point in using Try
is to work with total functions instead of partial functions that can throw exceptions.
答案2
得分: 1
我不太了解vavr,但在库的javadoc中查看,你可以看到onFailure方法将一个Consumer<? super Throwable>作为参数。问题在于,消费者不声明已检查的异常,所以你永远无法从你的lambda中抛出已检查的异常。
话虽如此,在这些情况下,我通常做的是创建一个"包装"类,该类将接受已检查的异常,这个包装类将只是捕捉任何已检查的异常并将它们包装在运行时异常中。例如:
public class ThrowingConsumerHelper {
public static <T> Consumer<T> throwingConsumer(
ThrowingConsumer<T> consumer) {
return object -> {
try {
consumer.accept(object);
} catch (Throwable t) {
throw new RuntimeException(t);
}
};
}
@FunctionalInterface
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
}
然后像这样使用它:
import static ThrowingConsumerHelper.throwingConsumer;
public static void main(String[] args) {
onFailure(throwingConsumer(object -> { throw new Exception("Bug"); }));
}
public static void onFailure(Consumer<? super Throwable> consumer) {
// Do something
}
希望这可以帮助你。
英文:
I don't know much about vavr, but looking in the javadoc for the library, you can see the onFailure method takes a Consumer<? super Throwable> as a parameter. The problem is that consumers do not declare checked exceptions, so you will never be able throw checked exceptions from your lambda.
That being said, what I generally do in these cases is I create a "wrapping" class that will accept checked exceptions, all this wrapping class will do is catch any checked exceptions and wrap them in a runtime exception. For example:
public class ThrowingConsumerHelper {
public static <T> Consumer<T> throwingConsumer(
ThrowingConsumer<T> consumer) {
return object -> {
try {
consumer.accept(object);
} catch (Throwable t) {
throw new RuntimeException(t);
}
};
}
@FunctionalInterface
public interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
}
And then use this like this:
import static ThrowingConsumerHelper.throwingConsumer;
public static void main(String[] args) {
onFailure(throwingConsumer(object -> { throw new Exception("Bug"); }));
}
public static void onFailure(Consumer<? super Throwable> consumer) {
// Do something
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论