Как вернуть первое возникшее исключение?

Есть метод validate, который в качестве входных данных принимает экземпляр Option и Predicate - два аргумента (да, я знаю Option должны быть переданы в качестве аргумента, но это упрощенный сценарий реального мира здесь. Сейчас если Option пусто мне нужно бросить NotFoundException, Когда оно имеет значение, которое не соответствует Predicate прошло это должно потерпеть неудачу с ForbiddenException, Если оно имеет значение и соответствует предикату, ничего не происходит.

Так что это будет:

                Option, Predicate
                     /\
          isEmpty() /  \ isDefined()  
                   /    \
            throw NFE    matches(Predicate)
                        / \
                    no /   \ yes 
                      /     \
                throw FE     end

У меня есть некоторые решения, но я хотел бы, чтобы потенциальные ответчики пришли к этому вопросу с ясным умом;) Моя проблема - получить первое исключение, если оба теста не пройдены. Я ожидаю элегантного решения, если я могу ожидать чего-либо;) Все существа вавр позволили (Either, Validation, Try..)

Одна из идей заключается в использовании двойного Option:

Option
  .of(o.getOrElseThrow(NotFoundException::new))
  .filter(p)
  .getOrElseThrow(ForbiddenException::new);

Но это кажется немного неловким.

Здесь образец проекта можно найти.

3 ответа

На мой взгляд, лучшим вариантом было бы создать читаемый код, что в данном случае означает использование двух if заявления:

if (!o.isPresent()) throw new NotFoundException();
if (!p.test(o.get())) throw new ForbiddenException();

Простой, читаемый и понятный для тех, кому понадобится сохранить этот код в будущем.

Если, тем не менее, вы хотите сделать это в каком-то функциональном стиле:

o.orElseThrow(NotFoundException::new);
o.filter(p).orElseThrow(ForbiddenException::new);

С Java 9:

o.ifPresentOrElse(
    t -> if (!p.test(t)) throw new ForbiddenException(), 
    () -> throw new NotFoundException());

Это было бы решением с Optional (нет времени проверять vavr но должно быть достаточно близко)

public static <T> void validate( Optional<T> optional, Predicate<T> pred ) throws NotFoundException, ForbiddenException {
    if ( !pred.test( optional.orElseThrow( NotFoundException::new ) ) )
        throw new ForbiddenException();
}

Не знаю, какой красивый способ бросить это ForbiddenException к несчастью.

Если вы хотите полнофункциональное решение, вам понадобится Optional

Optional.of( 
    pred.test( 
       option.orElseThrow( NotFoundException::new ) 
    ) 
).filter( b -> b ).orElseThrow( ForbiddenException::new );

Исключение выдается в правильном порядке, так как мы проверяем только Predicate после option проверять.

final CheckedFunction2<Option<T>, Predicate<T>, T> 
    f = (option, predicate) ->
    Try.of(() -> option.getOrElseThrow(NotFoundException::new))
       .filter(predicate, ForbiddenException::new)
       .get();
Другие вопросы по тегам