Что делает ключевое слово Java assert и когда оно должно использоваться?
На каких реальных примерах можно понять ключевую роль утверждений?
20 ответов
Утверждения (посредством ключевого слова assert) были добавлены в Java 1.4. Они используются для проверки правильности инварианта в коде. Они никогда не должны запускаться в рабочем коде и указывают на ошибку или неправильное использование пути кода. Они могут быть активированы во время выполнения посредством -ea
вариант на java
команда, но не включены по умолчанию.
Пример:
public Foo acquireFoo(int id) {
Foo result = null;
if (id > 50) {
result = fooService.read(id);
} else {
result = new Foo(id);
}
assert result != null;
return result;
}
Предположим, что вы должны написать программу для управления атомной электростанцией. Совершенно очевидно, что даже самая незначительная ошибка может привести к катастрофическим результатам, поэтому ваш код должен быть без ошибок (при условии, что JVM не содержит ошибок ради аргумента).
Java не является проверяемым языком, что означает: вы не можете рассчитать, что результат вашей работы будет идеальным. Основной причиной этого являются указатели: они могут указывать куда угодно или никуда, поэтому они не могут быть рассчитаны как имеющие именно это значение, по крайней мере, в пределах разумного диапазона кода. Учитывая эту проблему, нет никакого способа доказать, что ваш код в целом верен. Но что вы можете сделать, это доказать, что вы, по крайней мере, обнаружите каждую ошибку, когда она случится.
Эта идея основана на парадигме Design-by-Contract (DbC): вы сначала определяете (с математической точностью), что должен делать ваш метод, а затем проверяете это, проверяя его во время фактического выполнения. Пример:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
return a + b;
}
Хотя это совершенно очевидно, что работает нормально, большинство программистов не увидят скрытую ошибку внутри этой (подсказка: Ariane V разбился из-за аналогичной ошибки). Теперь DbC определяет, что вы всегда должны проверять ввод и вывод функции, чтобы убедиться, что она работает правильно. Java может сделать это с помощью утверждений:
// Calculates the sum of a (int) + b (int) and returns the result (int).
int sum(int a, int b) {
assert (Integer.MAX_VALUE - a >= b) : "Value of " + a + " + " + b + " is too large to add.";
final int result = a + b;
assert (result - a == b) : "Sum of " + a + " + " + b + " returned wrong sum " + result;
return result;
}
Если эта функция теперь когда-нибудь выйдет из строя, вы заметите это. Вы будете знать, что в вашем коде есть проблема, вы знаете, где она находится, и вы знаете, что ее вызвало (похоже на исключения). И что еще более важно: вы перестаете работать правильно, когда это происходит, чтобы предотвратить дальнейший код, работающий с неправильными значениями, и потенциально нанести ущерб всему, что он контролирует.
Исключения Java представляют собой похожую концепцию, но они не в состоянии проверить все. Если вы хотите еще больше проверок (за счет скорости выполнения), вам нужно использовать утверждения. Это приведет к раздуванию вашего кода, но в итоге вы сможете доставить продукт на удивительно короткое время разработки (чем раньше вы исправите ошибку, тем ниже будет стоимость). И дополнительно: если в вашем коде есть какая-либо ошибка, вы ее обнаружите. Нет никакого способа проскочить ошибку и вызвать проблемы позже.
Это все еще не является гарантией для кода без ошибок, но гораздо ближе к этому, чем обычные программы.
Утверждения - это инструмент фазы разработки для выявления ошибок в вашем коде. Они предназначены для легкого удаления, поэтому они не будут существовать в рабочем коде. Таким образом, утверждения не являются частью "решения", которое вы предоставляете клиенту. Это внутренние проверки, чтобы убедиться, что ваши предположения верны. Наиболее распространенным примером является проверка на ноль. Многие методы написаны так:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Очень часто в таком методе виджет никогда не должен быть нулевым. Так что, если он нулевой, в вашем коде есть ошибка, которую нужно отследить. Но код выше никогда не скажет вам этого. Поэтому, стараясь написать "безопасный" код из благих намерений, вы также скрываете ошибку. Гораздо лучше написать такой код:
/**
* @param Widget widget Should never be null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
... // do more stuff with this widget
}
Таким образом, вы наверняка поймаете эту ошибку раньше. (Также полезно указать в контракте, что этот параметр никогда не должен быть нулевым.) Обязательно включайте утверждения при тестировании кода во время разработки. (И убедить ваших коллег сделать это тоже часто бывает сложно, что я нахожу очень раздражающим.)
Теперь некоторые из ваших коллег будут возражать против этого кода, утверждая, что вы все равно должны поставить нулевую проверку, чтобы предотвратить исключение в рабочей среде. В этом случае утверждение все еще полезно. Вы можете написать это так:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
... // do more stuff with this widget
}
}
Таким образом, ваши коллеги будут рады, что для производственного кода есть нулевая проверка, но во время разработки вы больше не будете скрывать ошибку, когда виджет равен нулю.
Вот реальный пример: я однажды написал метод, который сравнивал два произвольных значения на равенство, где любое значение могло быть нулевым:
/**
* Compare two values using equals(), after checking for null.
* @param thisValue (may be null)
* @param otherValue (may be null)
* @return True if they are both null or if equals() returns true
*/
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = thisValue.equals(otherValue);
}
return result;
}
Этот код делегирует работу equals()
метод в случае, когда thisValue не является нулевым. Но это предполагает equals()
метод правильно выполняет контракт equals()
путем правильной обработки нулевого параметра.
Коллега возразил против моего кода, сказав, что во многих наших классах есть ошибки equals()
методы, которые не проверяют на ноль, поэтому я должен поместить эту проверку в этот метод. Это спорный вопрос, если это имеет смысл, или если мы должны заставить эту ошибку, так что мы можем обнаружить его и исправить ее, но я отложила мой коллега и поставить в нулевом чеке, который я пометил с комментарием:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
} else {
result = otherValue != null && thisValue.equals(otherValue); // questionable null check
}
return result;
}
Дополнительная проверка здесь, other != null
, необходимо только если equals()
Метод не может проверить на ноль, как того требует его контракт.
Вместо того, чтобы вступать в бесполезную дискуссию с моим коллегой о целесообразности сохранения ошибочного кода в нашей кодовой базе, я просто вставляю в него два утверждения. Эти утверждения сообщат мне на этапе разработки, если один из наших классов не сможет реализовать equals()
правильно, так что я могу это исправить:
public static boolean compare(final Object thisValue, final Object otherValue) {
boolean result;
if (thisValue == null) {
result = otherValue == null;
assert otherValue == null || otherValue.equals(null) == false;
} else {
result = otherValue != null && thisValue.equals(otherValue);
assert thisValue.equals(null) == false;
}
return result;
}
Важные моменты, которые следует иметь в виду:
Утверждения являются только инструментами фазы разработки.
Смысл утверждения в том, чтобы вы знали, есть ли ошибка не только в вашем коде, но и в вашей кодовой базе. (Утверждения здесь будут фактически отмечать ошибки в других классах.)
Даже если бы мой коллега был уверен, что наши занятия написаны правильно, утверждения здесь все равно будут полезны. Будут добавлены новые классы, которые могут не пройти проверку на null, и этот метод может пометить эти ошибки для нас.
В процессе разработки вы всегда должны включать утверждения, даже если в написанном вами коде утверждения не используются. Моя IDE по умолчанию всегда делает это для любого нового исполняемого файла.
Утверждения не меняют поведение кода в рабочей среде, поэтому мой коллега рад, что проверка на ноль есть, и что этот метод будет выполняться правильно, даже если
equals()
метод глючит. Я счастлив, потому что я поймаю любой баггиequals()
метод в разработке.
Кроме того, вы должны проверить свою политику утверждений, вставив временное утверждение, которое не будет выполнено, чтобы вы могли быть уверены, что вас уведомят либо через файл журнала, либо через трассировку стека в выходном потоке.
Много хороших ответов, объясняющих, что assert
ключевое слово, но мало кто отвечает на реальный вопрос, "когда следует assert
ключевое слово будет использоваться в реальной жизни?
Ответ: почти никогда.
Утверждения, как концепция, прекрасны. Хороший код имеет много if (...) throw ...
заявления (а их родственники любят Objects.requireNonNull
а также Math.addExact
). Тем не менее, некоторые конструктивные решения значительно ограничивают полезность assert
самоключевое слово.
Идея вождения позади assert
Ключевое слово - преждевременная оптимизация, и главная особенность - возможность легко отключить все проверки. На самом деле, assert
проверки отключены по умолчанию.
Тем не менее, очень важно, чтобы инвариантные проверки продолжались в производстве. Это потому, что идеальное тестовое покрытие невозможно, и весь производственный код будет содержать ошибки, утверждения которых должны помочь в диагностике и смягчении.
Поэтому использование if (...) throw ...
должно быть предпочтительным, так же как это требуется для проверки значений параметров открытых методов и для броска IllegalArgumentException
,
Иногда может возникнуть соблазн написать инвариантную проверку, обработка которой занимает нежелательно много времени (и вызывается достаточно часто, чтобы это имело значение). Однако такие проверки замедляют тестирование, что также нежелательно. Такие трудоемкие проверки обычно записываются как модульные тесты. Тем не менее, иногда имеет смысл использовать assert
по этой причине.
Не использовать assert
просто потому, что он чище и красивее, чем if (...) throw ...
(и я говорю это с большой болью, потому что я люблю чистые и красивые). Если вы просто не можете себе помочь и можете контролировать запуск своего приложения, не стесняйтесь использовать assert
но всегда включайте утверждения в производстве. Правда, это то, что я склонен делать. Я настаиваю на аннотации ломбок, который приведет к assert
вести себя как if (...) throw ...
, Проголосуйте за это здесь.
(Rant: разработчики JVM были группой ужасных, преждевременно оптимизирующих кодеров. Вот почему вы слышите о столь многих проблемах безопасности в плагине Java и JVM. Они отказались включать базовые проверки и утверждения в производственный код, и мы продолжаем заплати цену.)
Вот наиболее распространенный вариант использования. Предположим, вы включаете значение enum:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
}
Пока вы справляетесь с каждым делом, вы в порядке. Но когда-нибудь кто-нибудь добавит fig к вашему enum и забудет добавить его в ваш оператор switch. Это приводит к ошибке, которую сложно поймать, потому что эффекты не будут ощущаться до тех пор, пока вы не оставите оператор switch. Но если вы напишите свой переключатель, как это, вы можете сразу же поймать его:
switch (fruit) {
case apple:
// do something
break;
case pear:
// do something
break;
case banana:
// do something
break;
default:
assert false : "Missing enum value: " + fruit;
}
Утверждения используются для проверки постусловий и предварительных условий "никогда не должно нарушаться". Правильный код никогда не должен ошибаться в утверждении; когда они срабатывают, они должны указывать на ошибку (возможно, в месте, близком к тому, где находится фактическое местоположение проблемы).
Примером утверждения может быть проверка того, что определенная группа методов вызывается в правильном порядке (например, что hasNext()
называется раньше next()
в Iterator
).
Что делает ключевое слово assert в Java?
Давайте посмотрим на скомпилированный байт-код.
Мы сделаем вывод, что:
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
генерирует почти тот же байт-код, что и:
public class Assert {
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
где Assert.class.desiredAssertionStatus()
является true
когда -ea
передается в командной строке и ложь в противном случае.
Мы используем System.currentTimeMillis()
чтобы не было оптимизировано (assert true;
сделал).
Синтетическое поле генерируется так, что Java нужно только вызвать Assert.class.desiredAssertionStatus()
один раз во время загрузки, а затем кеширует результат там. Смотрите также: Что означает "статический синтетический"?
Мы можем проверить это с помощью:
javac Assert.java
javap -c -constants -private -verbose Assert.class
В Oracle JDK 1.8.0_45 было сгенерировано синтетическое статическое поле (см. Также: Что означает "статический синтез"?):
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
вместе со статическим инициализатором:
0: ldc #6 // class Assert
2: invokevirtual #7 // Method java/lang Class.desiredAssertionStatus:()Z
5: ifne 12
8: iconst_1
9: goto 13
12: iconst_0
13: putstatic #2 // Field $assertionsDisabled:Z
16: return
и основным методом является:
0: getstatic #2 // Field $assertionsDisabled:Z
3: ifne 22
6: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
9: lconst_0
10: lcmp
11: ifeq 22
14: new #4 // class java/lang/AssertionError
17: dup
18: invokespecial #5 // Method java/lang/AssertionError."<init>":()V
21: athrow
22: return
Мы заключаем, что:
- нет поддержки уровня байт-кода
assert
: это концепция языка Java assert
может быть эмулировано довольно хорошо со свойствами системы-Pcom.me.assert=true
заменить-ea
в командной строке иthrow new AssertionError()
,
Утверждение позволяет обнаруживать дефекты в коде. Вы можете включить утверждения для тестирования и отладки, оставляя их отключенными, когда ваша программа находится в работе.
Зачем утверждать что-то, когда вы знаете, что это правда? Это правда только тогда, когда все работает правильно. Если программа имеет дефект, это может быть на самом деле не так. Обнаружение этого ранее в процессе позволяет понять, что что-то не так.
assert
заявление содержит это утверждение вместе с необязательным String
сообщение.
Синтаксис оператора assert имеет две формы:
assert boolean_expression;
assert boolean_expression: error_message;
Вот некоторые основные правила, которые определяют, где утверждения должны использоваться, а где они не должны использоваться. Утверждения должны использоваться для:
Проверка входных параметров частного метода. НЕ для публичных методов.
public
методы должны генерировать регулярные исключения, когда передаются неверные параметры.В любом месте в программе, чтобы обеспечить достоверность факта, который почти наверняка верно.
Например, если вы уверены, что это будет только 1 или 2, вы можете использовать утверждение вроде этого:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "cannot happen. i is " + i;
}
...
- Проверка почтовых условий в конце любого метода. Это означает, что после выполнения бизнес-логики вы можете использовать утверждения, чтобы гарантировать, что внутреннее состояние ваших переменных или результатов соответствует ожидаемому. Например, метод, открывающий сокет или файл, может использовать утверждение в конце, чтобы убедиться, что сокет или файл действительно открыт.
Утверждения не должны использоваться для:
Проверка входных параметров открытого метода. Поскольку утверждения не всегда могут быть выполнены, следует использовать механизм регулярных исключений.
Проверка ограничений на то, что вводится пользователем. То же, что и выше.
Не следует использовать для побочных эффектов.
Например, это неправильное использование, потому что здесь утверждение используется для побочного эффекта вызова doSomething()
метод.
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
Единственный случай, когда это может быть оправдано, это когда вы пытаетесь выяснить, включены ли утверждения в вашем коде:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Assertions are enabled");
} else {
System.out.println("Assertions are disabled");
}
Пример из реального мира из класса Stack (из утверждения в статьях Java)
public int pop() {
// precondition
assert !isEmpty() : "Stack is empty";
return stack[--num];
}
В дополнение ко всем отличным ответам, представленным здесь, официальное руководство по программированию на Java SE 7 содержит довольно краткое руководство по использованию. assert
; с несколькими точными примерами того, когда это хорошая (и, что важно, плохая) идея использовать утверждения, и как это отличается от создания исключений.
Assert очень полезен при разработке. Вы используете его, когда что-то просто не может произойти, если ваш код работает правильно. Он прост в использовании и может оставаться в коде навсегда, потому что он будет отключен в реальной жизни.
Если есть вероятность, что это состояние может возникнуть в реальной жизни, то вы должны справиться с этим.
Я люблю это, но не знаю, как включить его в Eclipse/Android/ADT . Кажется, он выключен даже при отладке. (На этом есть поток, но он ссылается на "Java vm", который не отображается в конфигурации запуска ADT).
Утверждения - это проверки, которые могут быть отключены. Они редко используются. Зачем?
- Их нельзя использовать для проверки аргументов открытых методов, поскольку вы не можете их контролировать.
- Они не должны использоваться для простых проверок, таких как
result != null
так как такие проверки очень быстрые и вряд ли что-то можно сохранить.
Итак, что осталось? Дорогие чеки на условия действительно ожидаемые, чтобы быть правдой. Хорошим примером могут служить инварианты структуры данных, такой как RB-дерево. На самом деле, в ConcurrentHashMap
JDK8, есть несколько таких значимых утверждений для TreeNodes
,
- Вы действительно не хотите включать их в производство, поскольку они могут легко доминировать во время выполнения.
- Вы можете включить или выключить их во время тестов.
- Вы определенно хотите включить их при работе над кодом.
Вот утверждение, которое я написал на сервере для проекта Hibernate/SQL. Компонент-сущность имеет два фактически булевых свойства: isActive и isDefault. Каждый из них может иметь значение "Y" или "N" или ноль, что рассматривается как "N". Мы хотим убедиться, что клиент браузера ограничен этими тремя значениями. Итак, в мои сеттеры для этих двух свойств я добавил это утверждение:
assert new HashSet<String>(Arrays.asList("Y", "N", null)).contains(value) : value;
Обратите внимание на следующее.
Это утверждение только для этапа разработки. Если клиент отправляет неверное значение, мы поймем это рано и исправим это задолго до того, как достигнем производства. Утверждения относятся к дефектам, которые вы можете обнаружить рано.
Это утверждение медленное и неэффективное. Это нормально. Утверждения могут быть медленными. Нам все равно, потому что это инструменты только для разработки. Это не замедлит рабочий код, потому что утверждения будут отключены. (Есть некоторые разногласия по этому вопросу, к которым я вернусь позже.) Это приводит к моей следующей точке.
Это утверждение не имеет побочных эффектов. Я мог бы проверить свою ценность на основании неизменяемого статического окончательного набора, но этот набор остался бы в производстве, где он никогда не использовался бы.
Это утверждение существует для проверки правильности работы клиента. Таким образом, к тому времени, когда мы достигнем производства, мы будем уверены, что клиент работает правильно, поэтому мы можем безопасно отключить утверждение.
Некоторые люди спрашивают это: если утверждение не нужно в производстве, почему бы просто не убрать их, когда вы закончите? Потому что они все еще понадобятся вам, когда вы начнете работать над следующей версией.
Некоторые люди утверждают, что вы никогда не должны использовать утверждения, потому что вы никогда не можете быть уверены, что все ошибки исчезли, поэтому вы должны держать их рядом даже в производстве. И поэтому нет смысла использовать оператор assert, поскольку единственное преимущество утверждений состоит в том, что вы можете отключить их. Следовательно, в соответствии с этим мнением, вы (почти) никогда не должны использовать утверждения. Я не согласен. Это правда, что если тест относится к производству, вы не должны использовать assert. Но этот тест не относится к производству. Эта ошибка предназначена для обнаружения ошибки, которая вряд ли когда-либо достигнет производства, поэтому ее можно безопасно отключить, когда вы закончите.
Кстати, я мог бы написать это так:
assert value == null || value.equals("Y") || value.equals("N") : value;
Это хорошо только для трех значений, но если число возможных значений становится больше, версия HashSet становится более удобной. Я выбрал версию HashSet, чтобы сделать вывод об эффективности.
Вот еще один пример. Я написал метод, который находит медиану значений в двух отсортированных массивах. Метод предполагает, что массивы уже отсортированы. По соображениям производительности НЕ следует сначала сортировать массивы или даже проверять их сортировку. Однако вызов этого метода с несортированными данными - серьезная ошибка, и мы хотим, чтобы эти ошибки были обнаружены на ранней стадии, на этапе разработки. Итак, вот как я справился с этими, казалось бы, противоречивыми целями:
public static int medianOf(int[] a, int[] b) {
assert assertionOnlyIsSorted(a); // Assertion is order n
assert assertionOnlyIsSorted(b);
... // rest of implementation goes here. Algorithm is order log(n)
}
public static boolean assertionOnlyIsSorted(int[] array) {
for (int i=1; i<array.length; ++i) {
if (array[i] < array[i-1]) {
return false;
}
return true;
}
}
Таким образом, медленный тест выполняется только на этапе разработки, где скорость менее важна, чем выявление ошибок. Вы хотите
medianOf()
чтобы иметь производительность log(n), но тест "отсортировано" имеет порядок n. Поэтому я помещаю его в утверждение, чтобы ограничить его использование фазой разработки, и даю ему имя, которое дает понять, что оно не подходит для производства.
Таким образом, у меня есть лучшее из обоих миров. В процессе разработки я знаю, что любой метод, вызывающий это неправильно, будет обнаружен и исправлен. И я знаю, что медленный тест не повлияет на производительность в продакшене. (Это также хорошая иллюстрация того, почему вы хотите оставить утверждения в рабочей среде, но включить их в разработке.)
Напомним (и это верно для многих языков, не только Java):
"assert" в основном используется в качестве средства отладки разработчиками программного обеспечения во время процесса отладки. Assert-сообщения никогда не должны появляться. Многие языки предоставляют опцию времени компиляции, которая заставит игнорировать все "утверждения" для использования при создании "производственного" кода.
"Исключения" - это удобный способ обработки всевозможных состояний ошибок, независимо от того, представляют ли они логические ошибки или нет, потому что, если вы столкнетесь с состоянием ошибок, которое вы не сможете продолжить, вы можете просто "выбросить их в воздух", "откуда бы вы ни были, ожидая, что кто-то еще будет готов" поймать "их. Управление передается за один шаг, прямо из кода, который вызвал исключение, прямо в перчатку ловца. (И ловец может видеть полный след звонков, которые имели место.)
Кроме того, вызывающим в этой подпрограмме не нужно проверять, удалось ли подпрограмма: "если бы мы были здесь сейчас, она должна была бы быть успешной, потому что в противном случае она вызвала бы исключение, и мы не были бы здесь сейчас!" Эта простая стратегия значительно упрощает разработку и отладку кода.
Исключения обычно позволяют условиям фатальной ошибки быть такими, как "исключения из правила". И для них должен обрабатываться кодовый путь, который также является "исключением из правила... " fly ball! "
Утверждения по умолчанию отключены. Чтобы включить их, мы должны запустить программу с -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 может быть любым выражением, возвращающим значение, я использовал его чаще, просто чтобы напечатать сообщение.
Утверждение в основном используется для отладки приложения или используется для замены обработки исключений для некоторых приложений для проверки действительности приложения.
Утверждение работает во время выполнения. Простой пример, который может очень просто объяснить всю концепцию, приведен ниже. Что делает ключевое слово assert в Java? (WikiAnswers).
Я не знаю, какая история стоит за этой функцией в Java. Но у меня есть идея о том, что
Скажем, у вас есть перечисление, которое вы включаете:(†)
public enum Veggie {
CAULIFLOWER,
CARROT,
}
// Another class
switch (veggie) {
case CAULIFLOWER: value = 5;
case CARROT: value = 3;
}
†: Возможно, хорошие компиляторы/инструменты Java будут статически отлавливать отсутствующие значения перечисления. В таком случае просто представьте, что вы нашли ошибку и исправляете ее. Затем вы можете добавить регрессионный тест в код, используя технику, описанную ниже.
Для этого нет хорошего случая по умолчанию . Таким образом, вы действительно хотите убедиться, что вы охватываете все значения. Вы хотите убедиться, что вы обновляете блок переключателя всякий раз, когда добавляете новый вариант перечисления:
public enum Veggie {
CAULIFLOWER,
CARROT,
TOMATO,
}
Но оказывается, что этот код вызывается прямо тогда, когда пользователь загружает конкретное представление в ваше веб-приложение. И представление может сохраняться, несмотря на эту ошибку: это было бы ошибкой, но не стоит вмешиваться в загрузку представления (скажем, пользователю просто представили несколько неправильных чисел). Итак, вы просто регистрируете предупреждение:
switch (veggie) {
case CAULIFLOWER: value = 5;
case CARROT: value = 3;
default: nonExhaustiveMatchOnEnum();
// […]
public static void nonExhaustiveMatchOnEnum() {
String errorMessage: "Missing veggie";
logger.warn(errorMessage);
}
Но вы хотите, чтобы этот сбой произошел сразу же, когда вы разрабатываете код — вы, разработчик, можете исправить такую ошибку за пять минут, в отличие от пользователей вашего веб-приложения.
Таким образом, вы можете просто добавить
public static void nonExhaustiveMatchOnEnum() {
String errorMessage: "Missing veggie";
assert false : errorMessage;
logger.warn(errorMessage);
}
Теперь приложение будет аварийно завершать работу локально, но будет регистрироваться только предупреждение в рабочей среде (при условии, что вы используете
По сути, "подтвердить истину" пройдет, а "подтвердить ложь" не удастся. Давайте посмотрим, как это будет работать:
public static void main(String[] args)
{
String s1 = "Hello";
assert checkInteger(s1);
}
private static boolean checkInteger(String s)
{
try {
Integer.parseInt(s);
return true;
}
catch(Exception e)
{
return false;
}
}
assert
это ключевое слово. Он был введен в JDK 1.4. Есть два типа assert
s
- Очень просто
assert
заявления - просто
assert
заявления.
По умолчанию все assert
заявления не будут выполнены. Если assert
оператор получает false, тогда он автоматически выдаст ошибку утверждения.