Когда использовать утверждение, а когда - исключение


121

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

Например,

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

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

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

Ответы:


81

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

Например, функция может делиться на 0, поэтому следует использовать исключение, но можно использовать утверждение для проверки того, что жесткий диск внезапно исчезает.

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

Обратите внимание, что if(group != null)это не утверждение, это просто условие.


3
«утверждение может быть использовано для проверки того, что жесткий диск внезапно пропадает» - я бы сказал, что это неверно: почему вы хотите, чтобы это обрабатывалось во время разработки, а не в производстве (когда утверждения обычно отключены)?
Herman

71
Комментарий о жестком диске неверен. Утверждения предназначены для проверки ошибок в логике вашего кода. Никогда и никогда не используйте их для проверки того, что вы не контролируете. Помните, что если утверждение не выполняется, это означает, что ваш код неверен .
Ian Goldby

1
@Marius Ваше условное выражение можно заменить утверждением вроде этого: assert group! =
Null

1
Проголосовали против, потому что пример жесткого диска противоречит вашей собственной философии. «Исчезновение» жестких дисков (с точки зрения кода) могло произойти в реальности - сколь бы маловероятным оно ни было. Как говорит @IanGoldby, утверждения должны зависеть исключительно от вещей, контролируемых вашим кодом.
Вики Чижвани

Гораздо лучший ответ, если бы он был написан Грегори Пакошем, прочтите этот пост.
ормурин 04

169

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

  • использовать исключения при проверке параметров, переданных общедоступным или защищенным методам и конструкторам
  • использовать исключения при взаимодействии с пользователем или когда вы ожидаете, что клиентский код восстановится после исключительной ситуации
  • используйте исключения для решения проблем, которые могут возникнуть
  • использовать утверждения при проверке предварительных условий, постусловий и инвариантов частного / внутреннего кода
  • используйте утверждения, чтобы оставить отзыв себе или своей команде разработчиков
  • используйте утверждения при проверке того, что вряд ли произойдет, иначе это означает, что в вашем приложении есть серьезный недостаток
  • используйте утверждения, чтобы утверждать, что вы (предположительно) знаете, что они правдивы

Другими словами, исключения направлены на надежность вашего приложения, а утверждения - на его правильность.

Утверждения разработаны таким образом, чтобы их можно было дешево писать, вы можете использовать их почти везде, и я использую это практическое правило: чем более глупо выглядит утверждение утверждения, тем оно ценнее и тем больше информации в него встроено. При отладке программы, которая ведет себя некорректно, вы обязательно проверите наиболее очевидные возможности отказа на основе вашего опыта. Затем вы проверите, нет ли проблем, которые просто не могут возникнуть: именно тогда утверждения очень помогают и экономят время.


53
Мне нравится, как вы это сформулировали: исключения определяют надежность вашего приложения, а утверждения - его правильность .
М. Дадли

Я кросс разместил это на своем сайте: pempek.net/articles/2013/11/16/assertions-or-exceptions
Грегори Пакош

И если вам посчастливилось искать настраиваемую библиотеку assert C ++, я выпустил github.com/gpakosz/Assert
Грегори Пакош

26

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

Также вам следует прочитать статью Oracle об assert, чтобы увидеть больше случаев, когда использовать - или не использовать - assert.


Hue hue hue Мне было интересно, почему мой код не работает в Eclipse, но отлично работает в командной строке.
Стив

15

Как общее правило:

  • Используйте утверждения для проверки внутренней согласованности, где вообще не имеет значения, отключит ли их кто-то. (Обратите внимание, что javaкоманда по умолчанию отключает все утверждения.)
  • Используйте регулярные тесты для любых проверок, которые нельзя отключать. Это включает в себя защитные проверки, которые защищают от потенциального ущерба, вызванного ошибками, и любые данные / запросы проверки / все, что предоставляется пользователями или внешними службами.

Следующий код из вашего вопроса плохой и потенциально ошибочный

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

Проблема в том, что вы НЕ ЗНАЕТЕ, что исключение означает, что группа не найдена. Также возможно, что service()вызов вызвал исключение или что он вернул, nullчто затем вызвало NullPointerException.

Когда вы перехватываете «ожидаемое» исключение, вы должны перехватывать только то исключение, которое вы ожидаете. Улавливая java.lang.Exception(и особенно не регистрируя ее), вы усложняете диагностику / отладку проблемы и потенциально позволяете приложению нанести больший ущерб.


4

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

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

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


ИМХО, проблема с такой рекомендацией заключается в том, что это нормально, если граница между публичной и частной частями API довольно фиксирована. Если вы разрабатываете новый код, эта граница часто бывает довольно плавной ...
Лен Холгейт

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

3

Согласно этому документу http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general , «утверждение assert подходит для закрытых предварительных условий, постусловий и инвариантов класса. Проверка. Общедоступная проверка предварительных условий должна по-прежнему выполняться с помощью проверок внутри методов, которые приводят, в частности, к документированным исключениям, таким как IllegalArgumentException и IllegalStateException ".

Если вы хотите узнать больше о предварительном условии, постусловии и инварианте класса, проверьте этот документ: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions . Он также содержит примеры использования утверждений.


1

Тестирование на null будет обнаруживать только нули, вызывающие проблемы, тогда как try / catch, как у вас, обнаружит любую ошибку.

В общем, try / catch безопаснее, но немного медленнее, и вы должны быть осторожны, чтобы не перехватить все виды ошибок, которые могут возникнуть. Поэтому я бы сказал, используйте try / catch - однажды код getGroup может измениться, и вам просто может понадобиться эта более крупная сеть.


1

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


1

Признаюсь, меня немного смутил ваш вопрос. Когда условие утверждения не выполняется, выдается исключение. Как ни странно, это называется AssertionError . Обратите внимание, что он не отмечен, например (например) IllegalArgumentException, которое возникает в очень похожих обстоятельствах.

Итак, используя утверждения в Java

  1. - более лаконичный способ написания блока условия / выброса
  2. позволяет включать / отключать эти проверки с помощью параметров JVM. Обычно я бы оставлял эти проверки включенными постоянно, если только они не влияют на производительность во время выполнения или не имеют аналогичных штрафов.

AssertionError - это подкласс Error, а не RuntimeException.
Stephen C

Ах. Конечно. Я думал о отмеченном / не отмеченном. Теперь исправлено
Брайан Агнью

Он объясняет, что такое утверждения (с противоречивой точки зрения), но не объясняет, когда именно их использовать.
Карл Рихтер

1

См. Раздел 6.1.2 (Утверждения и другие коды ошибок) документации Sun по следующей ссылке.

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

Этот документ дает лучший совет о том, когда использовать утверждения. Цитата из документа:

"Хорошее практическое правило заключается в том, что вы должны использовать утверждение в исключительных случаях, о которых вы хотели бы забыть. Утверждение - это самый быстрый способ справиться и забыть условие или состояние, которое, как вы не ожидаете, придется иметь дело с."


0

К сожалению, утверждения можно отключить. В процессе производства вам понадобится вся помощь, которую вы можете получить при отслеживании чего-то непредвиденного, поэтому утверждающие дисквалифицируют себя.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.