7

Что такое утверждения в Java и когда их следует использовать?

29

Какие есть реальные примеры, чтобы понять ключевую роль ключевого слова Java assert?

5 ответ(ов)

0

Утверждения (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:

0

Вот самый распространенный случай использования. Предположим, вы используете оператор 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, что значительно упростит отладку.

0

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

Пример утверждения может заключаться в проверке, что определенная группа методов вызывается в правильном порядке (например, что hasNext() вызывается перед next() в Iterator).

0

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

Зачем утверждать что-то, если вы уверены, что это истинно? Это истинно только в случае, если всё работает правильно. Если в программе есть дефект, это может оказаться не так. Выявление этого на ранней стадии процесса позволяет понять, что-то идет не так.

Утверждение (assert) содержит условие, а также необязательное сообщение типа String.

Синтаксис утверждения имеет две формы:

assert boolean_expression;
assert boolean_expression: error_message;

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

  1. Валидации входных параметров закрытого метода. НЕ для публичных методов. Публичные методы должны выбрасывать обычные исключения при передаче недопустимых параметров.
  2. В любом месте программы для проверки истинности факта, который почти наверняка верен.

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

...
if (i == 1) {
    ...
}
else if (i == 2) {
    ...
} else {
    assert false : "не должно происходить. i равно " + i;
}
...
  1. Валидации постусловий в конце любого метода. Это означает, что после выполнения бизнес-логики вы можете использовать утверждения, чтобы убедиться, что внутреннее состояние ваших переменных или результатов соответствует вашим ожиданиям. Например, метод, который открывает сокет или файл, может использовать утверждение в конце, чтобы подтвердить, что сокет или файл действительно открыты.

Утверждения не должны использоваться для:

  1. Валидации входных параметров публичного метода. Поскольку утверждения могут не всегда выполняться, следует использовать обычный механизм исключений.
  2. Валидации ограничений на что-то, что вводит пользователь. То же самое, что и выше.
  3. Не следует использовать для побочных эффектов.

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

public boolean doSomething() {
    ...
}
public void someMethod() {
    assert doSomething();
}

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

boolean enabled = false;
assert enabled = true;
if (enabled) {
    System.out.println("Утверждения включены");
} else {
    System.out.println("Утверждения отключены");
}
0

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

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

Что касается включения Assert в Eclipse/Android/ADT, это действительно может быть неочевидно. Чтобы включить проверки утверждений, вам нужно сделать следующее:

  1. Откройте конфигурацию запуска вашего проекта, кликнув правой кнопкой мыши по проекту и выбрав Run As > Run Configurations....
  2. В открывшемся окне выберите вашу конфигурацию запуска.
  3. Перейдите на вкладку Arguments.
  4. В поле VM arguments добавьте следующую строку: -ea (это флаг, который включает проверку утверждений).

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

Если у вас будут еще вопросы, не стесняйтесь спрашивать!

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь