Есть ли прекрасный способ утвердить предварительные условия в Java-методах?
Многие мои функции имеют целую нагрузку кода проверки чуть ниже деклараций:
if ( ! (start < end) ) {
throw new IllegalStateException( "Start must be before end." );
}
Я хотел бы точно указать допустимые диапазоны определенных входных данных - например, A > B, C = > 1 или str_d.length() > 0.
Учитывая, что некоторые из моих функций имеют довольно много аргументов, которые должны быть проверены, я могу закончить писать много котельной пластины только для проверки предварительных условий. Я пишу библиотеку, которая, в основном, будет использоваться нетехническими разработчиками, мы обнаружили, что проверка правильности входных данных - лучший способ помочь нашим пользователям правильно управлять нашим API. Чем скорее мы поднимем ошибку, тем меньше будет работать наша клиентка.
Есть ли более элегантный метод для определения предварительных условий, пост-условий (и, возможно, инвариантных условий) в моих методах.
Коллега рассказал мне об особенностях языка программирования Эйфеля, который позволяет описать предварительные/пост-инвариантные условия очень естественным образом, не повторяя много шаблонов. Есть ли дополнение к языку Java, которое позволит мне использовать некоторые из этих магии?
Ответы
Ответ 1
Guava Preconditions класс просто для этого. Обычно вы используете его со статическим импортом, поэтому ваш пример будет выглядеть так:
checkArgument(start < end, "Start must be before end");
Это упрощает добавление дополнительной информации в сообщение, не оплачивая стоимость конкатенации String
, если проверка проходит.
checkArgument(start < end, "Start (%s) must be before end (%s)", start, end);
В отличие от операторов assert
, они не могут быть отключены.
Ответ 2
Просмотрите проект Cofoja, который предоставляет контракты для Java через аннотации. Он предоставляет Pre-/Postconditions и Invariants. Кроме того, в отличие от других реализаций Java, он правильно обрабатывает контракты, определенные в родительских классах/интерфейсах. Оценка контракта может быть включена/отключена во время выполнения.
Вот фрагмент кода из учебник:
import com.google.java.contract.Invariant;
import com.google.java.contract.Requires;
@Invariant("size() >= 0")
interface Stack<T> {
public int size();
@Requires("size() >= 1")
public T pop();
public void push(T obj);
}
Ответ 3
Как насчет assert start < end
. Посмотрите документацию.
Ответ 4
Аспектно-ориентированное программирование может быть использовано для такой проблемы. Вызов метода может быть перехвачен проверкой на инвариант. Пояснения и советы настраиваются декларативным способом. Spring и Guice делают использование АОП простым.
Здесь пример в Guice.
Ответ 5
Возможно, вы сможете сделать это с помощью аннотации и ориентированного на аспект программирования.
Я бы использовал исключение IllegalArgumentException, если комбинация аргументов не является законной. Я использовал бы IllegalStateException в состоянии, которое мешает работе метода.
Вы можете создать вспомогательный метод для исключения.
public static void check(boolean test, String message) {
if(!test) throw new IllegalArgumentException(message);
}
check(start < end, "Start must be before end.");
Ответ 6
Для проверки ввода вы также можете использовать Apache Commons Validator.
Обратите внимание, что входная проверка всегда должна быть включена. Следовательно, он концептуально отличается от проверки утверждения (как, например, в Eiffel), которая может быть необязательно включена/выключена - см. Ответ на этот связанный вопрос о переполнении стека Когда следует использовать Apache Commons 'Validate.isTrue, и когда следует использовать ключевое слово' assert '?
Ответ 7
Если я обнаружил, что повторяю один и тот же код проверки предварительного кода котельной в классе, я реорганизую свой код, чтобы уменьшить дублирование и увеличить абстракцию, извлекая повторяющийся код в новый (static private
) метод. Я использую метод Java-7 Objects.requireNonNull
для проверок null
.
Ответ 8
Пакет JUnit имеет такие конструкции, как assert, которые помогут выполнить проверку состояния.