Как войти только определенное исключение с vavr - PullRequest
1 голос
/ 22 октября 2019

Итак, у меня есть метод, который возвращает 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 был успешным, и если это был сбой, регистрируйте ошибку, если ошибка 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 возвращает Try, поэтому вызывающий не может знать, что FailedRequestException является частью возможных сбоев,Я могу позволить fetchData вернуть Try<Either<FailedRequestException, Data>>, но это тоже не правильно. Есть ли способ сделать вышесказанное более элегантным способом? Я также пытался использовать Match и Case, но Case ожидает Function в качестве обработчика, а не Consumer.

1 Ответ

2 голосов
/ 22 октября 2019

Подводя итог: на самом деле у вас есть 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 семейство функций.

ура!

...