1

所以我有一个返回 Vavr 的方法Try

public Try<Result> request() {...}

request来自我无法修改的来源。目前,我对结果进行平面映射,request并根据是否Result有错误返回Try异常或成功返回来自以下的数据Result

public Try<Data> fetchData() {
    return request().flatMap(result -> {
        if (result.hasError()) {
            return Try.failure(new FailedRequestException());
        } else {
            return Try.success(result.data());
        }
    });
}

我想要的是在某些地方fetchData首先使用数据,如果Try成功,如果失败,则记录错误,如果错误是 a FailedRequestException,否则,除异常外,执行其他操作,如下所示:

fetchData().andThen(data -> ...).onFailure(ex -> {
    if (ex instanceOf FailedRequestException) {
        log.error("Could not fetch data: " + ex.getMessage());
    } else {
        // Do something with the exception
        ...
    }
});

我对这种方法的问题是fetchData返回 aTry所以调用者无法知道 aFailedRequestException是可能失败的一部分。我可以让fetchDatareturn aTry<Either<FailedRequestException, Data>>但这也感觉不对。有没有办法以更优雅的方式完成上述操作?我也尝试使用MatchandCaseCase期望 aFunction作为处理程序而不是Consumer.

4

1 回答 1

2

总结一下:您实际上有 3 种情况(成功、FailedRequestException 失败、任何其他失败)。这听起来像是模式匹配的工作!让我们让代码像业务需求一样可见和富有表现力:)

Match(fetchData()).of(
    Case($Success($()), data -> doStuff(data)),
    Case($Failure($(instanceOf(FailedRequestException.class))), fre -> logFreAndReturnValue(fre)),
    Case($Failure($()), e -> doSomethingWithOtherException(e))
);

FWIW,您可以fetchData这样重写您的实现:

Try(request())
    .mapFailure(Case($(), ignored -> new FailedRequestException()))
    .map(Result::data);

根据经验,flatMap当上下文(成功或失败)可能发生变化时,尽量坚持使用。在您当前fetchData的实现中,成功仍然是成功,失败仍然是失败,因此它是输入和输出之间的映射map,因此使用函数族。

干杯!

于 2019-10-22T17:20:43.017 回答