Ярлык для Guava Дополнительное использование с исключениями?
Я продолжаю писать специальные исключения в случае, если опция отсутствует.
Например:
Optional<?> optional = ...;
if (!optional.isPresent()) {
throw new MyException();
}
Object result = optional.get();
Я нахожу этот код не очень бегло, особенно использование взрыва (!). Я бы предпочел написать что-то вроде:
Optional<?> optional = ...;
Object result = optional.orThrow(MyException.class);
Есть ли такой ярлык в Guava, который я еще не нашел?
Ответы
Ответ 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());