Наконец, у меня есть вопрос спросить о переполнении стека!: -)
Основная цель для Java, но я считаю, что это в основном языковой агностик: если у вас нет встроенного assert, вы всегда можете имитировать его.
Я работаю в компании, продающей набор программных продуктов, написанных на Java. Код старый, по крайней мере, начиная с Java 1.3, и в некоторых местах он показывает... Это большая база кода, около 2 миллионов строк, поэтому мы не можем реорганизовать все сразу.
В последнее время мы переключили последние версии с синтаксиса Java 1.4 и JVM на Java 1.6, сделав консервативное использование некоторых новых функций, таких как assert
(мы использовали макрос DEBUG.ASSERT - я знаю, что assert
был введен в 1.4 но мы не использовали его раньше), generics (только типизированные коллекции), foreach loop, перечисления и т.д.
Я все еще немного зелёный об использовании assert, хотя я прочитал пару статей по этой теме. Тем не менее, некоторые виды использования, которые я вижу, оставляют меня недоумением, наносят вред здравому смыслу... ^ _ ^ Поэтому я подумал, что должен задать несколько вопросов, посмотреть, правильно ли я хочу исправлять материал, или если это противоречит обычным практикам. Я многословен, поэтому я полужирный вопросы, для тех, кому нравится снимать вещи.
Для справки, я искал assert java в SO и нашел интересные потоки, но, по-видимому, нет точного дубликата.
- Как избежать инструкций "!= Null" в java? и Сколько нулевой проверки достаточно? достаточно актуальны, потому что много утверждений мы просто проверяем, переменная имеет значение null. В некоторых местах нашего кода есть использование нулевого объекта (например, возврат
new String[0]
), но не всегда. Мы должны жить с этим, по крайней мере, для поддержания устаревшего кода. - Некоторые хорошие ответы также содержатся в недопонятые утверждения Java.
- О, и SO указывает, что Когда следует использовать Debug.Assert()? вопрос (очень хорошая функция для сокращения дубликатов!).
Во-первых, главный вопрос, который вызвал мой вопрос сегодня:
SubDocument aSubDoc = documents.GetAt( i );
assert( aSubDoc != null );
if ( aSubDoc.GetType() == GIS_DOC )
{
continue;
}
assert( aSubDoc.GetDoc() != null );
ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();
(Да, мы используем условные обозначения MS/C/С++. И мне даже нравится (исходя из того же фона)! Так подавайте нам в суд.)
Во-первых, форма assert()
происходит от преобразования вызовов DEBUG.ASSERT()
. Мне не нравятся дополнительные круглые скобки, поскольку assert - это языковая конструкция, а не (уже не здесь) вызов функции. Мне тоже не нравится return (foo);
:-)
Далее, утверждения не проверяют здесь для инвариантов, они скорее используются в качестве защитников от плохих значений. Но, как я понимаю, они бесполезны здесь: утверждение будет генерировать исключение, даже не документированное со строкой-компаньоном, и только если утверждения включены. Поэтому, если у нас есть опция -ea
, у нас просто есть утверждение, которое вызывается вместо обычного NullPointerException. Это не похоже на первостепенное преимущество, так как в любом случае мы исключаем неконтролируемые исключения на самом высоком уровне.
Правильно ли я полагаю, что мы можем избавиться от них и жить с этим (т.е. позволить Java поднимать такое исключенное исключение)? (или, конечно, тест против нулевого значения, если это возможно, что делается в других места).
Боковое примечание: следует ли мне утверждать в приведенном выше фрагменте, я бы сделал это против значения ci, а не против геттера: даже если большинство геттеров оптимизировано/включено, мы не можем быть уверены, поэтому нам следует избегать двойного вызова.
Кто-то сказал в последнем упоминаемом потоке, что публичные методы должны использовать тесты против значений параметров (использование публичного API), а частные методы должны полагаться только на утверждения. Хороший совет.
Теперь оба метода должны проверять другой источник данных: внешний вход. То есть. данные, поступающие от пользователя, из базы данных, например, из какого-либо файла или из сети.
В нашем коде я вижу утверждения против этих значений. Я всегда меняю их на реальный тест, поэтому они действуют даже с отключенными утверждениями: они не являются инвариантами и должны быть надлежащим образом обработаны.
Я вижу только одно возможное исключение, где ввод считается постоянным, например, таблица базы данных, заполненная константами, используемыми в отношениях: программа будет разбита, если эта таблица будет изменена, но соответствующий код не будет обновлен.
Вы видите другие исключения?
Еще одно относительно частое использование, которое я вижу, что кажется ОК: по умолчанию для коммутатора или в конце серии else if
тестирование всех возможных значений (эти случаи датируются до нашего использования перечислений!), там часто assert false : "Unexpected value for stuff: " + stuff;
Выглядит законно для меня (эти случаи не должны происходить в производстве), что вы думаете? (помимо "без коммутатора, используйте OO", которые здесь неактуальны).
И, наконец, есть ли какие-нибудь другие полезные примеры использования или раздражающие gotchas, которые я пропустил здесь? (Возможно!)