Подтвердить что ты не робот

Ярлык для Guava Дополнительное использование с исключениями?

Я продолжаю писать специальные исключения в случае, если опция отсутствует.

Например:

Optional<?> optional = ...;
if (!optional.isPresent()) {
  throw new MyException();
}
Object result = optional.get();

Я нахожу этот код не очень бегло, особенно использование взрыва (!). Я бы предпочел написать что-то вроде:

Optional<?> optional = ...;
Object result = optional.orThrow(MyException.class);

Есть ли такой ярлык в Guava, который я еще не нашел?

4b9b3361

Ответ 1

Говоря как разработчик Guava, позвольте мне попробовать распаковать здесь логику. Отвечая как на исходный вопрос, так и на поток комментариев непосредственно на вопрос:

Совершенно верно, что мы пытаемся заставить пользователей Guava уважать наши стандарты хороших привычек программирования. (На наши стандарты сильно влияет, например, эффективная Java.)

Тем не менее, я согласен с тем, что в этом конкретном вопросе есть совершенно хорошие варианты использования: "если отсутствует, выбросьте исключение". Возможно, вы реализуете класс, к которому можно получить доступ в обоих направлениях - один метод с необязательным возвращаемым значением и один метод, который предполагает, что значение всегда будет присутствовать, иначе исключая исключение. Интерфейс Deque, например, предоставляет специальные и исключающие исключения версии peek, poll и offer.

Все, что сказало, насколько мне известно, путь True Guava для этого - это...

if (value.isPresent()) {
  return value.get();
} else {
  throw new MyException();
}

Предлагаемый метод "orThrow" требует отражения (!!), не позволяет настраивать исключение с полезным сообщением и т.д. "Нормальный путь" отлично читается и более эффективен.

Иногда Guava не предоставляет явной поддержки для вещей, потому что для этих случаев использования мы считаем, что это лучше всего сделать только "обычным способом". Я думаю, что это так.

Ответ 2

Вот еще один способ сделать это без добавления в Guava:

Object result = optional.or(new Supplier() {
    public Object get() {
        throw new MyException();
    }
});

MyException должно быть отключено, но это позволяет передавать аргументы его конструктору. И, конечно, если вы делаете это много, вы можете хранить Поставщика где-то и использовать его в каждом месте, в котором оно вам нужно.

Object result = optional.or(SomethingIsMissing.INSTANCE);

Ответ 3

Нет ничего, что Java 8 Optional имеет метод orElseThrow, который позволяет запрашивать поведение.

Ответ 4

Я не думаю, что это будет принадлежать библиотеке. Мне очень редко приходится находить библиотеку, которая получает экземпляр исключения, которое может быть выбрано, если что-то не так, как ожидалось, особенно потому, что во многих случаях исключение должно иметь сообщение о том, что пошло не так.

При этом вы можете создать свой собственный дополнительный класс, который сделает все, что вам нужно. Или вы можете создать свой собственный класс OptionalHelper, где у вас есть метод, который делает то, что вы хотите:

public class OptionalHelper {
   public <T> T valueOrThrow(final Optional<T> optional) throws MyException {
      if (optional.isPresent()) {
          return optional.get();
      } else {
          throw new MyException();
      }
   }
}

EDIT:

Предположим, что у вас есть пользовательский класс, который получает имя параметра/поля, которое вам нужно проверить, вы могли бы лучше подойти к тому, что делает Preconditions:

public class OptionalHelper {
   public <T> T valueOrFail(final Optional<T> optional, final String fieldName) throws OptionalNotPresentError {
      if (optional.isPresent()) {
          return optional.get();
      } else {
          throw new OptionalNotPresentError(fieldName);
      }
   }
}

Ответ 5

Это работает для меня (нет отражения, просто введите вывод):

public class ExceptionSupplier<T, E extends RuntimeException> implements Supplier<T> {

    private final E exception;

    private ExceptionSupplier(E exception) {
        this.exception = exception;
    }

    public static <T, E extends RuntimeException> ExceptionSupplier<T, E> throwA(E exception) {
        return new ExceptionSupplier<T, E>(exception);
    }    

    public static <T, E extends RuntimeException> ExceptionSupplier<T, E> throwA(@SuppressWarnings("UnusedParameters") Class<T> class_, E exception) {
        return new ExceptionSupplier<T, E>(exception);
    }

    @Override
    public T get() {
        throw exception;
    }
}

Использование:

Something something = optionalSomething.or(throwA(Something.class, new SomeException()));

Это, вероятно, может быть расширено еще больше, но для моих случаев использования это достаточно и легко понять.

Ответ 6

См. официальная проблема здесь

Решение: НЕТ - слишком дорого, а не общий шаблон, может просто использовать! isPresent(), throw

Так как optional.orThrow(new Exception()) не подходит для производительности, я предпочитаю статический импорт, который похож на @timk answer.

Result result = optional.or(throwException());

Равенство

Result result = optional.or(SomeSupplier.throwException());

Статический метод

public static Supplier<Result> throwException() {
    return new Supplier<Result>() {
        @Override
        public Result get() {
            throw new RuntimeException();
        }

    };
}

===========

Трассировка стека выглядит как

Exception ... RuntimeException
at SomeSupplier$1.get(SomeSupplier.java:line where throw RuntimeException)
at SomeSupplier$1.get(SomeSupplier.java:1)
at com.google.common.base.Absent.or(Absent.java:60)
at line where call optional.or(throwException());