При каких условиях JVM выполняет проверку оператора assert в Java?
Оператор assert проверяется только при включённых утверждениях JVM. По умолчанию проверки отключены, поэтому выражение-условие не должно использоваться для обязательной бизнес-логики, валидации входных данных или других действий, необходимых при любом запуске программы.
Если проверка включена и условие ложно, JVM выбрасывает AssertionError. Если утверждения отключены, ошибка не возникает, а выражение условия обычно вообще не вычисляется.
Assertions появились в Java 1.4 как средство проверки внутренних предположений программы во время разработки и тестирования. Подход решал проблему обнаружения нарушений инвариантов без обязательных затрат и изменения поведения production-запуска.
Отключённое по умолчанию выполнение сохранило совместимость: добавление assert-проверок в существующий код не должно было внезапно менять его рабочую семантику или требовать обработки новых исключений.
Разработчик может ошибочно воспринимать assert как сокращённую форму обязательной проверки. Например, проверка аргумента публичного метода через assert будет пропущена в обычном запуске, если утверждения не включены.
Особый риск возникает, когда в условии есть побочный эффект. При отключённых assertions такой эффект не произойдёт, поэтому состояние программы начнёт зависеть от параметров запуска JVM.
JVM поддерживает режимы включения и отключения утверждений. При включённом режиме она вычисляет условие assert; если результат равен false, создаётся и выбрасывается AssertionError. Необязательное сообщение вычисляется только при обнаружении ложного условия.
При отключённых assertions проверка пропускается. Поэтому условие должно быть чистым: оно не должно менять состояние, выполнять запись, вызывать обязательную очистку ресурсов или содержать другую логику, на которую рассчитывает программа.
При включённых assertions вызов завершится с AssertionError. При отключённых программа напечатает сообщение, несмотря на отрицательное значение.
Для обязательной проверки внешних данных следует использовать обычную логику валидации и подходящее исключение, например IllegalArgumentException. Assert подходит для внутренних инвариантов, которые указывают на ошибку в самой программе: недостижимую ветку, нарушение предположения алгоритма или некорректное состояние после внутренней операции.
Утверждения можно включать для всего приложения, пакета или конкретного класса и отдельно отключать. Это даёт гибкость для тестовых и диагностических запусков, но требует контролировать конфигурацию среды: отсутствие assertions в production не должно нарушать корректность работы.
В библиотеке разработчик проверил через assert, что публичный метод получает положительный размер страницы. При локальном запуске с включёнными assertions ошибка быстро обнаруживалась, но в production этот режим не был включён, и отрицательное значение доходило до расчёта смещения.
Рассматривались два варианта. Сохранить assert было удобно для внутреннего инварианта и почти не влияло на обычное выполнение, но решение не защищало публичный контракт. Заменить проверку на обязательную валидацию надёжнее для внешнего ввода, хотя это меняет поведение метода и требует явно определить тип ошибки.
Выбран второй вариант для аргумента публичного API, а assert оставлен только для последующей внутренней проверки состояния. В результате некорректный запрос стал предсказуемо отклоняться в любой среде, а assertions продолжили помогать находить ошибки реализации во время тестирования.
Нет, если корректность проверки обязательна. Assertions могут быть отключены, поэтому внешний вызывающий код не получит гарантированной защиты. Для аргументов публичного API нужна обычная проверка, например с выбрасыванием IllegalArgumentException.
Побочный эффект может не произойти вообще, когда assertions отключены. Поэтому такое выражение создаёт зависимость поведения программы от режима JVM и является ошибочным проектированием. В assert следует помещать только проверку, не влияющую на состояние программы.
AssertionError является наследником Error, а не Exception, и сигнализирует о нарушении предположения, которое обычно указывает на дефект программы. Исключение вроде IllegalArgumentException описывает некорректное использование API или входные данные и является частью ожидаемого контракта метода. Поэтому эти механизмы имеют разные семантические назначения, даже если оба могут прервать выполнение.