Ключевое слово assert (проверка) появилось в Java 1.4. Мне кажется, многие до сих пор стараются его избегать, или заворачивать в утилитные статические методы с возможностью быстро поменять
по всему коду. Кто-то боится, что проверки недостаточно надежные, и если кто-то забудет их включить, какие-то баги останутся незамеченными. Кто-то, наоборот, маниакально думает о производительности: если кто-то включит проверки для подсистемы/библиотеки, написанной ребятами из первой группы, и забудет исключить пакеты или классы «производительной» библиотеки, исполнение будет замедленно бесполезными вычислениями.
Хотя, по-моему, ничего страшного в проверках нет, их можно и нужно расставлять по коду как можно щедрее. Во-первых, как я уже упомянул (но для кого-то это может оказаться в новинку), проверки можно гибко настраивать (включать/отключать в пакетах и отдельных классах) как из командной строки при запуске JVM, так и программно (через ClassLoader), так что если вы вдруг захотите включить проверки в одной системе и выключить — в другой, это уж точно решаемая проблема.
Во-вторых, иногда хочется проверять не тривиальные условия вроде
Трюк прост: инициализация и обновление проверочного состояния выносится в методы, которые по смыслу ничего не возвращают (
Пример:
assert condition : message; наif (!condition) throw new AssertionError(message);
по всему коду. Кто-то боится, что проверки недостаточно надежные, и если кто-то забудет их включить, какие-то баги останутся незамеченными. Кто-то, наоборот, маниакально думает о производительности: если кто-то включит проверки для подсистемы/библиотеки, написанной ребятами из первой группы, и забудет исключить пакеты или классы «производительной» библиотеки, исполнение будет замедленно бесполезными вычислениями.
Хотя, по-моему, ничего страшного в проверках нет, их можно и нужно расставлять по коду как можно щедрее. Во-первых, как я уже упомянул (но для кого-то это может оказаться в новинку), проверки можно гибко настраивать (включать/отключать в пакетах и отдельных классах) как из командной строки при запуске JVM, так и программно (через ClassLoader), так что если вы вдруг захотите включить проверки в одной системе и выключить — в другой, это уж точно решаемая проблема.
Во-вторых, иногда хочется проверять не тривиальные условия вроде
какая-то булева переменная == false или true, а поддерживать некоторое проверочное состояние внутри класса и сверяться с ним в методах. С помощью трюка с assert можно добиться этого практически бесплатно при исполнении с отключенными проверками.Трюк прост: инициализация и обновление проверочного состояния выносится в методы, которые по смыслу ничего не возвращают (
void), а в коде — boolean и всегда true. Эти методы вызываются «через» assert. То есть, когда проверки для класса отключены, методы не вызываются, проверочное состояние не инициализируется и не обновляется, и в накладных расходах остается только одна null-ссылка в памяти объекта.Пример:
import java.util.HashSet; import java.util.Set; public final class MyCoolSet<E> { private Object[] coolStorage; private transient Set<E> referenceSet; public MyCoolSet() { // ... init cool storage assert initReferenceSet(); } private boolean initReferenceSet() { referenceSet = new HashSet<>(); return true; } public int size() { // return the cool size return 42; } public boolean add(E e) { // .. add an element to the cool storage boolean added = true; assert addToReferenceSet(e); return added; } private boolean addToReferenceSet(E e) { referenceSet.add(e); checkSize(); return true; } private void checkSize() { assert referenceSet.size() == size() : "Cool size diverged from reference size"; } public boolean remove(Object o) { // ... remove an element from the cool storage boolean removed = true; assert removeFromReferenceSet(o); return removed; } private boolean removeFromReferenceSet(Object o) { referenceSet.remove(o); checkSize(); return true; } }