Try.of() 失败时如何抛出异常?

How to throw exception when Try.of() fails?

如果 Try.ofCallable() 失败,我想抛出从 Exception 扩展的异常。

我有一个可调用类型:

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

如果 MyRuntimeExceptionAMyRuntimeExceptionB 都扩展了 RuntimeException,这将起作用(包装上述两个语句的函数抛出正确的异常 MyRuntimeExceptionA 和 MyRuntimeExceptionB),但如果它们扩展 Exception.

如果它们扩展 Exception 那么我就不能将它们从主函数中抛出。 IDE 要求将它们包装在 try/catch 中——我不想要。

我不太了解 vavr,但是查看库的 javadoc,您可以看到 onFailure 方法采用 Consumer 作为参数。问题是消费者不声明已检查的异常,因此您永远无法从 lambda 中抛出已检查的异常。

也就是说,在这些情况下我通常做的是创建一个“包装”class 来接受已检查的异常,所有这些包装 class 将捕获所有已检查的异常并且将它们包装在运行时异常中。例如:

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
    }

你有两个选择。当您尝试通过使用以下代码获取值来解包 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 的全部意义在于使用总函数而不是可能引发异常的部分函数。