Что такое утверждения в Java и когда их следует использовать?
Какие есть реальные примеры, чтобы понять ключевую роль ключевого слова Java assert
?
5 ответ(ов)
Утверждения (assertions) — это инструмент, используемый на этапе разработки для выявления ошибок в вашем коде. Их основное предназначение — быть легко удаляемыми, чтобы они не находились в производственном коде. Таким образом, утверждения не являются частью "решения", которое вы предоставляете заказчику. Это внутренние проверки, позволяющие убедиться, что ваши предположения верны. Наиболее распространенный пример — проверка на null. Многие методы пишутся следующим образом:
void doSomething(Widget widget) {
if (widget != null) {
widget.someMethod(); // ...
// ... Делаем что-то еще с этим виджетом
}
}
Очень часто в подобных методах виджет просто не должен быть null. Если он равен null, значит, в вашем коде есть ошибка, которую нужно отследить. Но приведенный выше код никогда не укажет вам на это. Таким образом, в стремлении написать "безопасный" код, вы также скрываете ошибку. Гораздо лучше написать код так:
/**
* @param Widget widget Не должен быть null
*/
void doSomething(Widget widget) {
assert widget != null;
widget.someMethod(); // ...
// ... Делаем что-то еще с этим виджетом
}
Таким образом, вы сможете поймать эту ошибку на раннем этапе. (Также полезно указать в контракте, что этот параметр не должен быть null.) Обязательно включайте утверждения, когда тестируете свой код в процессе разработки. (Убедить ваших коллег делать это тоже часто бывает сложно, и это мне очень раздражает.)
Теперь некоторые ваши коллеги могут возразить против такого кода, утверждая, что вам все же следует реализовать проверку на null, чтобы предотвратить исключение в производственной среде. В таком случае утверждение все еще будет полезным. Вы можете написать код так:
void doSomething(Widget widget) {
assert widget != null;
if (widget != null) {
widget.someMethod(); // ...
// ... Делаем что-то еще с этим виджетом
}
}
Таким образом, ваши коллеги будут довольны тем, что проверка на null присутствует в производственном коде, но во время разработки вы больше не скрываете ошибку, когда виджет равен null.
Вот пример из реальной практики: я однажды написал метод, который сравнивает два произвольных значения на равенство, при этом любое из значений могло быть null:
Вот самый распространенный случай использования. Предположим, вы используете оператор switch
для обработки значения перечисления:
switch (fruit) {
case apple:
// что-то сделать
break;
case pear:
// что-то сделать
break;
case banana:
// что-то сделать
break;
}
Если вы обрабатываете все возможные случаи, то все в порядке. Но однажды кто-то может добавить fig
в ваше перечисление и забыть добавить его в ваш switch
. Это может привести к ошибке, которую будет сложно отследить, так как последствия проявятся только после выхода из оператора switch
. Но если вы напишете свой switch
таким образом, вы сможете поймать эту ошибку сразу:
switch (fruit) {
case apple:
// что-то сделать
break;
case pear:
// что-то сделать
break;
case banana:
// что-то сделать
break;
default:
assert false : "Пропущено значение перечисления: " + fruit;
}
Таким образом, при добавлении нового значения в перечисление, вы сразу получите ошибку, если забудете обновить свой оператор switch
, что значительно упростит отладку.
Утверждения (assertions) используются для проверки постусловий и "не должны никогда срабатывать" для предусловий. Правильный код никогда не должен приводить к срабатыванию утверждения; когда они срабатывают, это должно указывать на наличие ошибки (надеемся, в месте, близком к реальному источнику проблемы).
Пример утверждения может заключаться в проверке, что определенная группа методов вызывается в правильном порядке (например, что hasNext()
вызывается перед next()
в Iterator
).
Утверждения позволяют выявлять дефекты в коде. Вы можете включать их для тестирования и отладки, оставляя выключенными, когда ваша программа находится в рабочем режиме.
Зачем утверждать что-то, если вы уверены, что это истинно? Это истинно только в случае, если всё работает правильно. Если в программе есть дефект, это может оказаться не так. Выявление этого на ранней стадии процесса позволяет понять, что-то идет не так.
Утверждение (assert
) содержит условие, а также необязательное сообщение типа String
.
Синтаксис утверждения имеет две формы:
assert boolean_expression;
assert boolean_expression: error_message;
Вот несколько основных правил, которые определяют, где должны использоваться утверждения, а где нет. Утверждения должны использоваться для:
- Валидации входных параметров закрытого метода. НЕ для публичных методов. Публичные методы должны выбрасывать обычные исключения при передаче недопустимых параметров.
- В любом месте программы для проверки истинности факта, который почти наверняка верен.
Например, если вы уверены, что переменная может принимать только значения 1 или 2, вы можете использовать такое утверждение:
...
if (i == 1) {
...
}
else if (i == 2) {
...
} else {
assert false : "не должно происходить. i равно " + i;
}
...
- Валидации постусловий в конце любого метода. Это означает, что после выполнения бизнес-логики вы можете использовать утверждения, чтобы убедиться, что внутреннее состояние ваших переменных или результатов соответствует вашим ожиданиям. Например, метод, который открывает сокет или файл, может использовать утверждение в конце, чтобы подтвердить, что сокет или файл действительно открыты.
Утверждения не должны использоваться для:
- Валидации входных параметров публичного метода. Поскольку утверждения могут не всегда выполняться, следует использовать обычный механизм исключений.
- Валидации ограничений на что-то, что вводит пользователь. То же самое, что и выше.
- Не следует использовать для побочных эффектов.
Например, это не корректное использование, потому что здесь утверждение используется для его побочного эффекта - вызова метода doSomething()
.
public boolean doSomething() {
...
}
public void someMethod() {
assert doSomething();
}
Единственный случай, когда это можно оправдать, это если вы пытаетесь узнать, включены ли утверждения в вашем коде:
boolean enabled = false;
assert enabled = true;
if (enabled) {
System.out.println("Утверждения включены");
} else {
System.out.println("Утверждения отключены");
}
Assert
действительно очень полезен при разработке. Вы используете его, когда что-то не может произойти, если ваш код работает правильно. Это просто в использовании, и может оставаться в коде навсегда, потому что в реальных условиях он будет отключен.
Если есть хоть малейшая возможность того, что условие может произойти в реальной жизни, то вы обязаны его обработать.
Что касается включения Assert
в Eclipse/Android/ADT, это действительно может быть неочевидно. Чтобы включить проверки утверждений, вам нужно сделать следующее:
- Откройте конфигурацию запуска вашего проекта, кликнув правой кнопкой мыши по проекту и выбрав
Run As > Run Configurations...
. - В открывшемся окне выберите вашу конфигурацию запуска.
- Перейдите на вкладку
Arguments
. - В поле
VM arguments
добавьте следующую строку:-ea
(это флаг, который включает проверку утверждений).
После этого ваши утверждения будут активны даже при отладке. Не забудьте сохранить изменения и перезапустить ваше приложение, чтобы изменения вступили в силу.
Если у вас будут еще вопросы, не стесняйтесь спрашивать!
Инициализация ArrayList в одну строчку
Почему нет ConcurrentHashSet, если есть ConcurrentHashMap?
Как объявить массив в одну строку?
Загрузка JDK Java на Linux через wget приводит к отображению страницы лицензии вместо установки
Создание репозитория Spring без сущности