Есть ли красивый способ утверждать предварительные условия в методах Java? - PullRequest
11 голосов
/ 25 июля 2011

У многих моих функций есть полный код проверки прямо под объявлениями:

if ( ! (start < end) ) {
    throw new IllegalStateException( "Start must be before end." );
    }

Я бы хотел точно указать допустимые диапазоны определенных входов - например, A> B, C => 1 или str_d.length ()> 0.

Учитывая, что некоторые из моих функций имеют довольно много аргументов, которые должны быть проверены, я могу закончить тем, что напишу много шаблонов просто для проверки предварительных условий. Я пишу библиотеку, которая в основном будет использоваться нетехническими разработчиками, мы обнаружили, что проверка входных данных функций - лучший способ помочь нашим пользователям правильно работать с нашим API. Чем раньше мы выдадим ошибку, тем меньше работы придется выполнять нашим клиентам.

Существует ли более элегантный метод для указания предварительных условий, постусловий (и, возможно, инвариантных условий) в моих методах.

Коллега рассказал мне об одной из особенностей языка программирования Eiffel, которая позволяет пред / пост / инвариантным условиям описывать очень естественным образом, не повторяя много шаблонного кода. Существуют ли дополнения к языку Java, которые позволят мне использовать эту магию?

Ответы [ 8 ]

12 голосов
/ 25 июля 2011

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

checkArgument(start < end, "Start must be before end");

Это также позволяет легко добавить больше информации в сообщение, не оплачивая конкатенацию String, если проверкаpass.

checkArgument(start < end, "Start (%s) must be before end (%s)", start, end);

В отличие от assert операторов, их нельзя отключить.

6 голосов
/ 26 июля 2011

Ознакомьтесь с проектом Cofoja , который предоставляет контракты для Java с помощью аннотаций.Предоставляет предварительные / постусловия и инварианты.Также, в отличие от других реализаций 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);
}
5 голосов
/ 25 июля 2011

Аспектно-ориентированное программирование может использоваться для такой задачи.Вызовы методов могут быть перехвачены проверкой инварианта.Pointcuts и советы настроены декларативным способом. Spring и Guice делают использование AOP простым.

Вот пример в Guice .

5 голосов
/ 25 июля 2011

Как насчет assert start < end.Взгляните на документацию .

4 голосов
/ 25 июля 2011

Вы можете сделать это с помощью аннотаций и аспектно-ориентированного программирования.

Я бы использовал IllegalArgumentException, если комбинация аргументов недопустима.Я бы использовал IllegalStateException в состоянии, которое препятствует работе метода.

Вы можете создать вспомогательный метод для исключения.

public static void check(boolean test, String message) {
    if(!test) throw new IllegalArgumentException(message);
}

check(start < end, "Start must be before end.");
1 голос
/ 28 ноября 2014

Если я обнаружу, что повторяю тот же самый код проверки предварительных условий в классе, я реорганизую свой код, чтобы уменьшить дублирование и увеличить абстракцию, извлекая повторяющийся код в новый (static private) метод. Я использую метод Java-7 Objects.requireNonNull для проверок null.

1 голос
/ 27 апреля 2012

Для проверки ввода вы также можете использовать Apache Commons Validator .

Обратите внимание, что проверка входных данных всегда должна быть включена. Следовательно, концептуально он сильно отличается от проверки утверждений (как, например, в Eiffel), которая может быть дополнительно включена / выключена - см. Ответ на этот связанный вопрос переполнения стека Когда мне следует использовать Validate.isTrue из Apache Commons, а когда мне просто использовать ключевое слово assert?

0 голосов
/ 25 июля 2011

Пакет JUnit имеет конструкции типа assert, которые помогут выполнить такую ​​проверку состояния.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...