2011-02-01 4 views
2

В этом конкретном сценарии утверждают более подходящие исключения?Об утверждениях и исключениях; Java

Полагаю, что утверждение должно использоваться, когда программа FUBAR до такой степени, что она не может восстановиться и выйдет.

Мне также сказали, что всегда делали исключения для ясности и обработки сообщений об ошибках.

Есть ли тонкая грань между тем, когда использовать каждый? Есть ли пример, где утверждение должно использоваться вместо исключения безоговорочно?

public void subscribe(DataConsumer c) throws IllegalArgumentException { 
     if (c == null) { 
      // Almost certainly FUBAR 
      throw new IllegalArgumentException("Can't subscribe null as a DataConsumer. Object not initialized"); 
     } 

     if (dataConsumerList == null) { 
      // Definetely FUBAR 
      throw new IllegalArgumentException("Nothing to subscribe to. DataConsumerList is null"); 
     } 

     dataConsumerList.add(c); 
    } 
+0

Соответствующий вопрос по этой теме http://stackoverflow.com/questions/3806173/assert-keyword-in-java. – CoolBeans

ответ

4

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

В любом случае, утверждение все равно собирается выбросить исключение. Если вы абсолютно хотите взять JVM вниз прямо сейчас, вам нужно использовать что-то вроде Runtime.halt.

Так что я фанат исключений здесь, хотя я обычно используют NullPointerException, когда данный нулевой аргумент, и если dataConsumerList является частью вашего состояния то я бы лично использовать IllegalStateException дифференцировать эту ситуацию. (Это позор, что Java не имеет тот же ArgmentNullException, что .NET имеет, учитывая, что общий проверить это.)

Guava имеет полезный Preconditions класс, который позволяет записать это более лаконично:

public void subscribe(DataConsumer c) throws IllegalArgumentException { 
    Preconditions.checkNotNull(c, 
     "Can't subscribe null as a DataConsumer. Object not initialized"); 
    Preconditions.checkState(dataConsumerList != null, 
     "Nothing to subscribe to. DataConsumerList is null"); 
    dataConsumerList.add(c); 
} 
+0

Я не согласен с вашим сравнением, так как (как вы сказали) утверждение будет только порождать исключение, а нулевое разыменование вызовет неодинаковое исключение. Единственное главное отличие состоит в том, что исключение, которое генерирует утверждение, несет определенную информацию. – biziclop

+0

@biziclop: Нет, разница заключается в том, что если вы используете исключение напрямую, проверка всегда будет выполняться - тогда как с утверждениями вы можете отключить их, после чего вы можете в конечном итоге продолжать слепо с неверными данными некоторое время. .. возможно, развращение государства. Предположим, что 'c' имеет значение null, но' dataConsumerList' isnt 'в этом случае. Отключение утверждений может привести к проблеме намного позже, и к тому времени вы можете где-то сохранить недопустимые данные. –

+0

@biziclop, утверждение вызовет ошибку. –

1

Общее правило (копируется из here)

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

Исключения - это способ обработки ошибок, которые могут быть законным образом выполняться при времени выполнения, например. отказ от попыток подключения к некоторому серверу (который может не реагировать по разным причинам).

И есть лучший способ написать приведенный выше код, используя google-guavaPreconditions.checkNotNull() класс.

public void subscribe(DataConsumer c) throws IllegalArgumentException 
{ 
checkNotNull(c, "Can't subscribe null as a DataConsumer. Object not initialized"); 
checkNotNull(dataConsumerList , "Nothing to subscribe to. DataConsumerList is null"); 

dataConsumerList.add(c); 
} 
0

Если вы могли бы поставить это в английских терминов, использовать утверждают, для «Должен» (делась, сусло) и исключений для «Отта» (Надо бы, надо).

Используйте assert для остановки показа, критические условия, которые должны быть истинны для продолжения выполнения. Примерами могут быть то, что деление происходит правильно (подумайте об ошибке с чипом с плавающей запятой Intel) или что ваше соединение с базой данных не является нулевым после того, как вы правильно его открыли. Если это произошло, выполнение программы не должно продолжаться.

Используйте бросок для предсказуемых ошибок, которые могут обрабатывать ваши методы.Бросок является частью контракта, который объявляет вам и другим программистам, что могут возникнуть определенные типы ошибок (и что это не ваша ответственность).

В вашем примере, я предполагаю, что нулевой потребитель или пустой список никогда не должны происходить при нормальных обстоятельствах. Если моя догадка правильная, тогда вы хотели бы использовать здесь assert, объявляя, что subscribe() обработает ее.

Если моя догадка ошибочна и имеет место нулевой потребитель, скажем 1 из 50 раз, тогда бросок будет лучше, и вы объявляете, что subscribe() формирует контракт с вызывающим методом, посредством которого обрабатывается метод вызова Ошибка.

0

The Java technote Programming With Assertions содержит эту явную линию в отношении к usage:

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

Это должен быть довольно окончательный ответ на ваш вопрос.

Смежные вопросы