На каких реальных примерах можно понять ключевую роль утверждений?
java
assertions
Praveen
источник
источник
Ответы:
Утверждения (посредством ключевого слова assert ) были добавлены в Java 1.4. Они используются для проверки правильности инварианта в коде. Они никогда не должны запускаться в рабочем коде и указывают на ошибку или неправильное использование пути кода. Их можно активировать во время выполнения с помощью
-ea
параметраjava
команды, но по умолчанию они не включены.Пример:
источник
assert
для проверки параметров открытого метода ( docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html ). Это должно броситьException
вместо того, чтобы убить программу.This convention is unaffected by the addition of the assert construct. Do not use assertions to check the parameters of a public method. An assert is inappropriate because the method guarantees that it will always enforce the argument checks. It must check its arguments whether or not assertions are enabled. Further, the assert construct does not throw an exception of the specified type. It can throw only an AssertionError.
docs.oracle.com/javase/8/docs/technotes/guides/language/…Предположим, что вы должны написать программу для управления атомной электростанцией. Совершенно очевидно, что даже самая незначительная ошибка может привести к катастрофическим результатам, поэтому ваш код не должен содержать ошибок (при условии, что JVM не содержит ошибок в качестве аргумента).
Java не является проверяемым языком, что означает: вы не можете рассчитать, что результат вашей работы будет идеальным. Основной причиной этого являются указатели: они могут указывать куда угодно или никуда, поэтому они не могут быть рассчитаны как имеющие именно это значение, по крайней мере, в пределах разумного диапазона кода. Учитывая эту проблему, невозможно доказать, что ваш код в целом верен. Но что вы можете сделать, это доказать, что вы, по крайней мере, обнаружите каждую ошибку, когда она случится.
Эта идея основана на парадигме Design-by-Contract (DbC): вы сначала определяете (с математической точностью), что должен делать ваш метод, а затем проверяете это, проверяя его во время фактического выполнения. Пример:
Хотя это совершенно очевидно, что работает нормально, большинство программистов не увидят скрытую ошибку внутри этой (подсказка: Ariane V разбился из-за аналогичной ошибки). Теперь DbC определяет, что вы всегда должны проверять ввод и вывод функции, чтобы убедиться, что она работает правильно. Java может сделать это с помощью утверждений:
Если эта функция когда-нибудь выйдет из строя, вы заметите это. Вы будете знать, что в вашем коде есть проблема, вы знаете, где она находится, и вы знаете, что ее вызвало (похоже на исключения). И что еще более важно: вы перестаете работать правильно, когда это происходит, чтобы предотвратить дальнейший код, работающий с неправильными значениями, и потенциально нанести ущерб всему, что он контролирует.
Исключения Java представляют собой похожую концепцию, но они не в состоянии проверить все. Если вы хотите еще больше проверок (за счет скорости выполнения), вам нужно использовать утверждения. Это приведет к раздуванию вашего кода, но в итоге вы сможете доставить продукт на удивительно короткое время разработки (чем раньше вы исправите ошибку, тем ниже будет стоимость). И дополнительно: если в вашем коде есть какая-либо ошибка, вы ее обнаружите. Нет способа проскочить ошибку и вызвать проблемы позже.
Это все еще не является гарантией для кода без ошибок, но гораздо ближе к этому, чем обычные программы.
источник
new IllegalArgumentException
сообщение? Я имею в виду, помимо добавления othrows
к объявлению метода и коду для управления этим исключением где-то еще. Зачемassert
вставлять новые исключения? Или почему неif
вместоassert
? Не могу получить это :(a
может быть отрицательным. Второе утверждение бесполезно; для значений int всегда есть случай, когда a + b - b == a. Этот тест может провалиться только в случае поломки компьютера. Чтобы защититься от этой непредвиденной ситуации, вам необходимо проверить согласованность между несколькими процессорами.Утверждения - это инструмент фазы разработки для выявления ошибок в вашем коде. Они разработаны так, чтобы их можно было легко удалить, поэтому они не будут существовать в рабочем коде. Таким образом, утверждения не являются частью «решения», которое вы предоставляете клиенту. Это внутренние проверки, чтобы убедиться, что ваши предположения верны. Наиболее распространенным примером является проверка на ноль. Многие методы написаны так:
Очень часто в таком методе виджет никогда не должен быть нулевым. Так что, если он нулевой, в вашем коде есть ошибка, которую нужно отследить. Но код выше никогда не скажет вам этого. Поэтому, стараясь написать «безопасный» код, вы также скрываете ошибку. Гораздо лучше написать такой код:
Таким образом, вы наверняка поймаете эту ошибку раньше. (Также полезно указать в контракте, что этот параметр никогда не должен быть нулевым.) Обязательно включайте утверждения при тестировании кода во время разработки. (И убедить ваших коллег сделать это тоже часто бывает сложно, что меня очень раздражает.)
Теперь некоторые из ваших коллег будут возражать против этого кода, утверждая, что вы все равно должны поставить нулевую проверку, чтобы предотвратить исключение в работе. В этом случае утверждение все еще полезно. Вы можете написать это так:
Таким образом, ваши коллеги будут рады, что для производственного кода есть нулевая проверка, но во время разработки вы больше не скрываете ошибку, когда виджет равен нулю.
Вот пример из реальной жизни: я однажды написал метод, который сравнивал два произвольных значения на равенство, где любое значение могло быть нулевым:
Этот код делегирует работу
equals()
метода в случае, когда thisValue не является нулевым. Но предполагается, чтоequals()
метод правильно выполняет контрактequals()
, правильно обрабатывая нулевой параметр.Коллега возразил против моего кода, сказав, что во многих наших классах есть ошибочные
equals()
методы, которые не проверяют на ноль, поэтому я должен поставить эту проверку в этот метод. Это спорно , если это имеет смысл, или если мы должны заставить эту ошибку, так что мы можем обнаружить его и исправить ее, но я отложила мой коллега и поставить в проверке нулевой, который я пометил с комментарием:Дополнительная проверка здесь
other != null
необходима только в том случае, еслиequals()
метод не может проверить нулевое значение, как того требует его контракт.Вместо того, чтобы вступать в бесполезную дискуссию с моим коллегой о целесообразности сохранения ошибочного кода в нашей кодовой базе, я просто вставляю в него два утверждения. Эти утверждения сообщат мне на этапе разработки, если один из наших классов не будет реализован
equals()
должным образом, поэтому я могу это исправить:Важные моменты, которые следует иметь в виду:
Утверждения являются только инструментами фазы разработки.
Смысл утверждения в том, чтобы вы знали, есть ли ошибка не только в вашем коде, но и в вашей кодовой базе . (Утверждения здесь будут фактически отмечать ошибки в других классах.)
Даже если бы мой коллега был уверен, что наши занятия написаны правильно, утверждения здесь все равно будут полезны. Будут добавлены новые классы, которые могут не пройти проверку на null, и этот метод может пометить эти ошибки для нас.
В процессе разработки вы всегда должны включать утверждения, даже если в написанном вами коде утверждения не используются. Моя IDE по умолчанию всегда делает это для любого нового исполняемого файла.
Утверждения не изменяют поведение кода в производственной среде, поэтому мой коллега рад, что проверка на ноль есть, и что этот метод будет выполняться правильно, даже если
equals()
метод содержит ошибки. Я счастлив, потому что я поймаю любой ошибочныйequals()
метод в разработке.Кроме того, вы должны проверить свою политику утверждений, вставив временное утверждение, которое не будет выполнено, чтобы вы могли быть уверены, что вас уведомят либо через файл журнала, либо через трассировку стека в выходном потоке.
источник
Много хороших ответов, объясняющих, что
assert
делает ключевое слово, но мало отвечающих на реальный вопрос, «когдаassert
ключевое слово следует использовать в реальной жизни?»Ответ: почти никогда .
Утверждения, как концепция, прекрасны. Хороший код имеет много
if (...) throw ...
утверждений (и их родственники любятObjects.requireNonNull
иMath.addExact
). Однако некоторые дизайнерские решения значительно ограничивают полезность самогоassert
ключевого слова .Идея, стоящая за
assert
ключевым словом, заключается в преждевременной оптимизации, и главной особенностью является возможность легко отключить все проверки. На самом деле,assert
проверки отключены по умолчанию.Тем не менее, крайне важно, чтобы инвариантные проверки продолжались в производстве. Это потому, что идеальное тестовое покрытие невозможно, и весь производственный код будет содержать ошибки, утверждения которых должны помочь в диагностике и смягчении.
Следовательно, использование
if (...) throw ...
должно быть предпочтительным, так же как это требуется для проверки значений параметров открытых методов и для бросанияIllegalArgumentException
.Иногда может возникнуть соблазн написать инвариантную проверку, обработка которой занимает нежелательно много времени (и вызывается достаточно часто, чтобы это имело значение). Однако такие проверки замедляют тестирование, что также нежелательно. Такие трудоемкие проверки обычно записываются как модульные тесты. Тем не менее, иногда может иметь смысл использовать
assert
по этой причине.Не используйте
assert
просто потому, что он чище и красивее чемif (...) throw ...
(и я говорю это с большой болью, потому что мне нравится чистота и красота). Если вы просто не можете себе помочь и можете контролировать запуск своего приложения, тогда не стесняйтесь использовать,assert
но всегда включайте утверждения в работе. Правда, это то, что я склонен делать. Я настаиваю на аннотации lombok, которая заставитassert
действовать больше какif (...) throw ...
. Проголосуйте за это здесь.(Rant: разработчики JVM были группой ужасных, преждевременно оптимизирующих программистов. Вот почему вы слышали о столь многих проблемах безопасности в плагине Java и JVM. Они отказались включать базовые проверки и утверждения в производственный код, и мы продолжаем заплати цену.)
источник
catch (Throwable t)
. Нет причин не пытаться перехватывать, регистрировать или повторять попытки / восстанавливаться из OutOfMemoryError, AssertionError и т. Д.assert
ключевого слова плохо. Я отредактирую свой ответ, чтобы было более понятно, что я имею в виду ключевое слово, а не концепцию.Вот наиболее распространенный вариант использования. Предположим, вы включаете значение enum:
Пока вы справляетесь с каждым делом, вы в порядке. Но когда-нибудь кто-нибудь добавит fig в ваше перечисление и забудет добавить его в ваш оператор switch. Это приводит к ошибке, которую сложно поймать, потому что эффекты не будут ощущаться до тех пор, пока вы не оставите оператор switch. Но если вы напишите свой переключатель, как это, вы можете сразу же поймать его:
источник
AssertionError
если утверждения включены (-ea
). Каково желаемое поведение в производстве? Тихая неоперация и потенциальная катастрофа позже в исполнении? Возможно нет. Я бы предложил явноеthrow new AssertionError("Missing enum value: " + fruit);
.default
чтобы компилятор мог предупредить вас о пропущенных случаях. Вы можетеreturn
вместо этогоbreak
(возможно, потребуется извлечь метод), а затем обработать пропущенный случай после переключения. Таким образом, вы получите предупреждение и возможностьassert
.Утверждения используются для проверки постусловий и предварительных условий «никогда не должно нарушаться». Правильный код никогда не должен ошибаться в утверждении; когда они срабатывают, они должны указывать на ошибку (возможно, в месте, близком к тому, где находится фактическое местоположение проблемы).
Примером утверждения может быть проверка того, что определенная группа методов вызывается в правильном порядке (например, который
hasNext()
вызывается ранееnext()
в aIterator
).источник
Давайте посмотрим на скомпилированный байт-код.
Мы сделаем вывод, что:
генерирует почти тот же байт-код, что и:
где
Assert.class.desiredAssertionStatus()
,true
когда-ea
передается в командной строке, и ложь в противном случае.Мы используем,
System.currentTimeMillis()
чтобы убедиться, что он не будет оптимизирован (assert true;
сделал).Синтетическое поле генерируется так, что Java нужно вызывать
Assert.class.desiredAssertionStatus()
только один раз во время загрузки, а затем кэшировать результат там. Смотрите также: Что означает «статический синтетический»?Мы можем проверить это с помощью:
В Oracle JDK 1.8.0_45 было сгенерировано синтетическое статическое поле (см. Также: Что означает «статический синтез»? ):
вместе со статическим инициализатором:
и основным методом является:
Мы заключаем, что:
assert
: это концепция языка Javaassert
может быть достаточно хорошо эмулировано с системными свойствами-Pcom.me.assert=true
для замены-ea
в командной строке, и athrow new AssertionError()
.источник
catch (Throwable t)
пункт может также отследить нарушения утверждений? Для меня это ограничивает их полезность только тем случаем, когда тело утверждения занимает много времени, что редко.AssertionError
первое и перебросить его.Пример из реального мира из класса Stack (из утверждения в статьях Java )
источник
Утверждение позволяет обнаруживать дефекты в коде. Вы можете включить утверждения для тестирования и отладки, оставляя их отключенными, когда ваша программа находится в производстве.
Зачем утверждать что-то, когда вы знаете, что это правда? Это правда только тогда, когда все работает правильно. Если программа имеет дефект, это может быть на самом деле не так. Обнаружение этого ранее в процессе позволяет понять, что что-то не так.
assert
Заявление содержит это заявление вместе с дополнительнымString
сообщением.Синтаксис для оператора assert имеет две формы:
Вот некоторые основные правила, которые определяют, где утверждения должны использоваться, а где они не должны использоваться. Утверждения должны использоваться для:
Проверка входных параметров частного метода. НЕ для публичных методов.
public
методы должны генерировать регулярные исключения при передаче неверных параметров.В любом месте в программе, чтобы обеспечить достоверность факта, который почти наверняка верно.
Например, если вы уверены, что это будет только 1 или 2, вы можете использовать утверждение вроде этого:
Утверждения не должны использоваться для:
Проверка входных параметров публичного метода. Поскольку утверждения не всегда могут быть выполнены, следует использовать механизм регулярных исключений.
Проверка ограничений на то, что вводится пользователем. То же, что и выше.
Не следует использовать для побочных эффектов.
Например, это неправильное использование, потому что здесь утверждение используется для побочного эффекта вызова
doSomething()
метода.Единственный случай, когда это может быть оправдано, - это когда вы пытаетесь выяснить, включены ли утверждения в вашем коде:
источник
В дополнение ко всем отличным ответам, представленным здесь, официальное руководство по программированию на Java SE 7 содержит довольно краткое руководство по использованию
assert
; с несколькими точными примерами того, когда хорошая (и, что важно, плохая) идея использовать утверждения, и чем она отличается от создания исключений.Ссылка на сайт
источник
Assert очень полезен при разработке. Вы используете его, когда что-то просто не может произойти, если ваш код работает правильно. Он прост в использовании и может оставаться в коде навсегда, потому что он будет отключен в реальной жизни.
Если есть вероятность, что это состояние может возникнуть в реальной жизни, то вы должны справиться с этим.
Я люблю это, но не знаю, как включить его в Eclipse / Android / ADT. Кажется, он выключен даже при отладке. (На этом есть поток, но он ссылается на «Java vm», который не отображается в конфигурации запуска ADT).
источник
Вот утверждение, которое я написал на сервере для проекта Hibernate / SQL. Компонент-сущность имеет два фактически булевых свойства: isActive и isDefault. Каждый из них может иметь значение «Y» или «N» или ноль, что рассматривается как «N». Мы хотим убедиться, что клиент браузера ограничен этими тремя значениями. Итак, в мои сеттеры для этих двух свойств я добавил это утверждение:
Обратите внимание на следующее.
Это утверждение только для этапа разработки. Если клиент отправляет неверное значение, мы поймем это рано и исправим это задолго до того, как достигнем производства. Утверждения относятся к дефектам, которые вы можете обнаружить рано.
Это утверждение медленное и неэффективное. Это нормально. Утверждения могут быть медленными. Нам все равно, потому что это инструменты только для разработки. Это не замедлит рабочий код, потому что утверждения будут отключены. (Есть некоторые разногласия по этому вопросу, к которым я вернусь позже.) Это приводит к моей следующей точке.
Это утверждение не имеет побочных эффектов. Я мог бы проверить свою ценность на основании неизменяемого статического окончательного набора, но этот набор остался бы в производстве, где он никогда не использовался бы.
Это утверждение существует для проверки правильности работы клиента. Таким образом, к тому времени, когда мы достигнем производства, мы будем уверены, что клиент работает правильно, поэтому мы можем безопасно отключить утверждение.
Некоторые люди спрашивают это: если утверждение не нужно в производстве, почему бы просто не убрать их, когда вы закончите? Потому что они все еще понадобятся вам, когда вы начнете работать над следующей версией.
Некоторые люди утверждают, что вы никогда не должны использовать утверждения, потому что вы никогда не можете быть уверены, что все ошибки исчезли, поэтому вам нужно держать их рядом даже в производстве. И поэтому нет смысла использовать оператор assert, поскольку единственное преимущество утверждений состоит в том, что вы можете отключить их. Следовательно, в соответствии с этим мнением, вы (почти) никогда не должны использовать утверждения. Я не согласен. Это правда, что если тест относится к производству, вы не должны использовать assert. Но этот тест не относится к производству. Эта ошибка предназначена для обнаружения ошибки, которая вряд ли когда-нибудь достигнет производства, поэтому ее можно безопасно отключить, когда вы закончите.
Кстати, я мог бы написать это так:
Это хорошо только для трех значений, но если число возможных значений становится больше, версия HashSet становится более удобной. Я выбрал версию HashSet, чтобы сделать вывод об эффективности.
источник
HashSet
дает какое-либо преимущество в скорости передArrayList
. Кроме того, набор и список создания доминируют время поиска. Они будут в порядке, используя константу. Это все сказано +1.Утверждение в основном используется для отладки приложения или используется для замены обработки исключений для некоторого приложения для проверки действительности приложения.
Утверждение работает во время выполнения. Простой пример, который может очень просто объяснить всю концепцию, приведен ниже. Что делает ключевое слово assert в Java? (WikiAnswers).
источник
Утверждения по умолчанию отключены. Чтобы включить их, мы должны запустить программу с
-ea
параметрами (степень детализации можно варьировать). Например,java -ea AssertionsDemo
.Существует два формата использования утверждений:
assert 1==2; // This will raise an AssertionError
,assert 1==2: "no way.. 1 is not equal to 2";
это вызовет ошибку AssertionError с отображаемым сообщением, и, следовательно, будет лучше. Хотя фактический синтаксис - этоassert expr1:expr2
когда expr2 может быть любым выражением, возвращающим значение, я использовал его чаще, просто чтобы напечатать сообщение.источник
Напомним (и это верно для многих языков, не только Java):
«assert» в основном используется в качестве средства отладки разработчиками программного обеспечения во время процесса отладки. Assert-сообщения никогда не должны появляться. Многие языки предоставляют опцию времени компиляции, которая заставит игнорировать все «утверждения» для использования при генерации «производственного» кода.
«Исключения» - это удобный способ обработки всевозможных состояний ошибок, независимо от того, представляют ли они логические ошибки или нет, потому что, если вы столкнетесь с состоянием ошибок, которое вы не сможете продолжить, вы можете просто «выбросить их в воздух», «откуда бы вы ни были, ожидая, что кто-то еще будет готов« поймать »их. Управление передается за один шаг, прямо из кода, который вызвал исключение, прямо в перчатку ловца. (И ловец может видеть полный след звонков, которые имели место.)
Кроме того, вызывающим в этой подпрограмме не нужно проверять, успешно ли выполнена подпрограмма: «если бы мы были здесь сейчас, она должна была бы быть успешной, потому что в противном случае она вызвала бы исключение, и мы не были бы здесь сейчас!» Эта простая стратегия значительно упрощает разработку и отладку кода.
Исключения обычно позволяют условиям фатальной ошибки быть такими, как «исключения из правила». И для них должен обрабатываться кодовый путь, который также является «исключением из правила ... » fly ball! »
источник
Утверждения - это проверки, которые могут быть отключены. Они редко используются. Почему?
result != null
такие проверки очень быстрые, и вряд ли что-то можно сохранить.Итак, что осталось? Дорогие чеки на условия действительно ожидаемые, чтобы быть правдой. Хорошим примером будут инварианты структуры данных, такой как RB-дерево. На самом деле, в
ConcurrentHashMap
JDK8 есть несколько таких значимых утверждений дляTreeNodes
.Иногда чек не очень дорогой, но в то же время вы уверены, что он пройдет. В моем коде, например,
где я почти уверен, что у только что созданного списка есть уникальные элементы, но я хотел документировать и перепроверить его.
источник
В основном, «assert true» пройдет, а «assert false» потерпит неудачу. Давайте посмотрим, как это будет работать:
источник
assert
это ключевое слово. Он был введен в JDK 1.4. Есть два типаassert
сassert
утвержденияassert
заявления.По умолчанию все
assert
операторы не будут выполнены. Еслиassert
оператор получает false, он автоматически выдаст ошибку утверждения.источник