Утверждения Java недостаточно используются
Мне интересно, почему assert
ключевое слово в Java недостаточно используется? Я почти никогда не видел, чтобы они использовались, но я думаю, что они отличная идея. Я конечно очень предпочитаю краткость:
assert param != null : "Param cannot be null";
многословию:
if (param == null) {
throw new IllegalArgumentException("Param cannot be null");
}
Я подозреваю, что они недостаточно используются, потому что
- Они прибыли сравнительно поздно (Java 1.4), к тому времени многие люди уже установили свой стиль / привычку программирования на Java.
- Они отключены во время выполнения по умолчанию
11 ответов
Теоретически,утверждения для тестирования инвариантов- это предположения, которые должны быть верными, чтобы код выполнялся правильно.
Показанный пример проверяет правильность ввода, что не является типичным использованием утверждения, поскольку оно обычно предоставляется пользователем.
Утверждения, как правило, не используются в производственном коде, потому что есть издержки, и предполагается, что ситуации, когда инварианты терпят неудачу, были обнаружены как ошибки кодирования во время разработки и тестирования.
Ваше мнение о том, что они "опоздали" на java, также является причиной того, что их не так широко видели.
Кроме того, платформы модульного тестирования допускают, что некоторые программные утверждения должны быть внешними по отношению к тестируемому коду.
Это злоупотребление утверждениями, чтобы использовать их для проверки ввода пользователя. Бросать IllegalArgumentException
неправильный ввод более корректен, так как позволяет вызывающему методу перехватить исключение, отобразить ошибку и сделать все, что ему нужно (запросить ввод еще раз, выйти, что угодно).
Если этот метод является закрытым методом внутри одного из ваших классов, утверждение в порядке, потому что вы просто пытаетесь убедиться, что случайно не передали ему нулевой аргумент. Вы проверяете с включенными утверждениями, и когда вы проверили все пути, не пройдя утверждение, вы можете отключить их, чтобы не тратить на них ресурсы. Они также полезны как комментарии. assert
в начале метода есть хорошая документация для сопровождающих, что они должны следовать определенным предварительным условиям, и assert
в конце с постусловием документы, что метод должен делать. Они могут быть так же полезны, как комментарии; Более того, потому что с утверждениями они на самом деле проверяют то, что они документируют.
Утверждения предназначены для тестирования / отладки, а не для проверки ошибок, поэтому они по умолчанию отключены: чтобы люди не использовали утверждения для проверки ввода пользователя.
Из программирования с утверждениями
По умолчанию утверждения отключены во время выполнения. Два параметра командной строки позволяют выборочно включать или отключать утверждения.
Это означает, что если у вас нет полного контроля над средой выполнения, вы не можете гарантировать, что код подтверждения будет даже вызван. Утверждения предназначены для использования в тестовой среде, а не для производственного кода. Вы не можете заменить обработку исключений утверждениями, потому что если пользователь запускает ваше приложение с отключенными утверждениями (по умолчанию), весь код обработки ошибок исчезает.
В "Эффективной Java" Джошуа Блох предложил (в разделе "Проверка параметров на валидность") (что-то вроде простого правила для принятия) для открытых методов мы проверим аргументы и сгенерируем необходимое исключение, если оно будет признано недействительным, и для непубличных методов (которые не раскрываются, и вы, как пользователь их, должны обеспечить их валидность), мы можем вместо этого использовать утверждение.
ус
@ Дон, вы разочарованы тем, что утверждение по умолчанию отключено. Я также, и, таким образом, написал этот маленький плагин javac, который вставляет их (т.е. испускает байт-код для if (!expr) throw Ex
а не этот глупый байт-код assert.
Если вы включите fa.jar в ваш classpath во время компиляции кода Java, он сделает свое дело и затем скажет
Note: %n assertions inlined.
@ смотри http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions/ и, альтернативно, на github https://github.com/akuhn/javac
ТЛ; др
- Да, используйте тестирование утверждений в производстве, где это имеет смысл.
- Используйте другие библиотеки ( JUnit, AssertJ, Hamcrest и т. Д.) Вместо встроенных
assert
средство, если вы хотите.
Большинство других Ответов на этой странице выдвигают максиму "Утверждения, как правило, не используются в производственном коде". Хотя это верно в продуктивных приложениях, таких как текстовый процессор или электронная таблица, в пользовательских бизнес-приложениях, где так часто используется Java, утверждение - Тестирование в производстве чрезвычайно полезно и распространено.
Как и во многих принципах в мире программирования, то, что начинается в одном контексте, неверно истолковывается, а затем неправильно применяется в других контекстах.
Приложения для повышения производительности
Этот принцип "Утверждения, как правило, не используются в производственном коде", хотя и распространен, неверен.
Формализованное тестирование утверждений возникло с помощью таких приложений, как текстовый процессор, например Microsoft Word, или электронной таблицы, например Microsoft Excel. Эти приложения могут вызывать массив утверждений проверочных проверок при каждом нажатии клавиши пользователем. Такое экстремальное повторение сильно повлияло на производительность. Таким образом, только бета-версии таких продуктов в ограниченном выпуске имели включенные утверждения. Таким образом, максим.
Бизнес-приложения
Напротив, в бизнес-ориентированных приложениях для ввода данных, базы данных или другой обработки данных использование проверки утверждений на производстве чрезвычайно полезно. Незначительный удар по производительности делает его довольно практичным - и распространенным.
Тест бизнес-правил
Проверка ваших бизнес-правил во время выполнения в производстве вполне разумна, и ее следует поощрять. Например, если в счете-фактуре всегда должно быть одно или несколько элементов строки, запишите проверку утверждений, если число элементов счета-фактуры больше нуля. Если имя продукта должно быть не менее 3 символов или более, напишите утверждение, проверяющее длину строки. Такие испытания не оказывают существенного влияния на производительность в производстве.
Условия выполнения
Если ваше приложение ожидает, что определенные условия всегда будут выполняться, когда ваше приложение работает в рабочей среде, запишите эти ожидания в свой код в качестве проверочных проверок.
Если вы ожидаете, что эти условия могут быть разумно иногда провалены, не пишите тесты утверждений. Возможно, выбросить определенные исключения. Затем попытайтесь восстановить, где это возможно.
Sanity-чеки
Проверки работоспособности во время выполнения в производстве также вполне разумны, и их следует поощрять. Тестирование нескольких произвольных условий, которые невозможно представить себе как неправду, спасло мой бекон в бесчисленных ситуациях, когда происходило какое-то странное событие.
Например, тестирование того, что округление никеля (0,05) до пенни привело к получению никеля (0,05) в определенной библиотеке, помогло мне стать одним из первых, кто обнаружил недостаток технологии с плавающей запятой, который Apple выпустила в своей библиотеке Rosetta во время переход с PowerPC на Intel. Такой недостаток, достигающий публики, казался бы невозможным. Но, что удивительно, этот недостаток ускользнул от внимания первоначального поставщика, Transitive и Apple, а также разработчиков раннего доступа, тестировавших бета-версии Apple.
(Кстати, я должен упомянуть... никогда не используйте с плавающей запятой для денег, используйте BigDecimal
.)
Выбор рамок
Вместо того, чтобы использовать встроенный assert
средство, вы можете рассмотреть возможность использования другой платформы утверждений. У вас есть несколько вариантов, в том числе:
- JUnit
Увидеть:org.junit.jupiter.api.Assertions
, - AssertJ
Известный своим плавным беглым интерфейсом. - Hamcrest
Используется во многих языках (Java, Python, Ruby, Swift и т. Д.).
Или покатись. Сделайте небольшой класс для использования в вашем проекте. Что-то вроде этого.
package work.basil.example;
public class Assertions {
static public void assertTrue ( Boolean booleanExpression , CharSequence message ) throws java.lang.AssertionError {
if ( booleanExpression ) {
// No code needed here.
} else { // If booleanExpression is false rather than expected true, throw assertion error.
// FIXME: Add logging.
throw new java.lang.AssertionError( message.toString() );
}
}
}
Пример использования:
Assertions.assertTrue(
localTime.isBefore( LocalTime.NOON ) ,
"The time-of-day is too late, after noon: " + localTime + ". Message # 816a2a26-2b95-45fa-9b0a-5d10884d819d."
) ;
Ваши вопросы
Они прибыли сравнительно поздно (Java 1.4), к тому времени многие люди уже установили свой стиль / привычку программирования на Java.
Да, это совершенно верно. Многие были разочарованы API, разработанным Sun/JCP для проверки утверждений. Его дизайн был тусклым по сравнению с существующими библиотеками. Многие игнорировали новый API и придерживались известных инструментов (сторонних инструментов или мини-библиотеки, созданной самим собой).
По умолчанию они отключены во время выполнения.
В первые годы Java получила плохую репутацию из-за низкой скорости работы. По иронии судьбы, Java быстро превратилась в одну из лучших платформ для повышения производительности. Но плохой рэп тянулся как вонючий запах. Поэтому Sun крайне настороженно относится ко всему, что может каким-либо измеримым образом повлиять на производительность. Поэтому с этой точки зрения имеет смысл сделать по умолчанию отключение проверки утверждений.
Другая причина отключения по умолчанию могла быть связана с тем, что при добавлении нового средства подтверждения Sun похитила слово assert
, Это не было ранее зарезервированным ключевым словом и требовало одного из немногих изменений, когда-либо внесенных в язык Java. Название метода assert
использовались многими библиотеками и многими разработчиками в своем собственном коде. Для некоторого обсуждения этого исторического перехода, прочитайте эту старую документацию, Программирование с утверждениями.
Утверждения полезны, потому что они:
- ловить ошибки ПРОГРАММИРОВАНИЯ рано
- код документа с использованием кода
Думайте о них как о коде самопроверки. Если они терпят неудачу, это должно означать, что ваша программа сломана и должна остановиться. Всегда включайте их во время модульного тестирования!
В Pragmatic Programmer они даже рекомендуют запускать их в производство.
Оставьте утверждения включенными
Используйте утверждения, чтобы предотвратить невозможное.
Обратите внимание, что утверждения выдают AssertionError, если они терпят неудачу, поэтому не перехватываются catch Exception.
Я не уверен, почему вы потрудитесь написать утверждения, а затем заменить их стандартным условием if then, почему бы просто не написать условия как будто в первую очередь?
Утверждения предназначены только для тестирования, и у них есть два побочных эффекта: большие двоичные файлы и снижение производительности при включении (вот почему вы можете их отключить!)
Утверждения не должны использоваться для проверки условий, потому что это означает, что поведение вашего приложения отличается во время выполнения, когда утверждения включены / отключены - что является кошмаром!
Утверждения очень ограничены: вы можете тестировать только логические условия, и вам нужно каждый раз писать код для полезного сообщения об ошибке. Сравните это с assertEquals() в JUnit, который позволяет сгенерировать полезное сообщение об ошибке из входов и даже показать два входа рядом в IDE в среде выполнения JUnit.
Кроме того, вы не можете искать утверждения в любой IDE, которую я видел до сих пор, но каждая IDE может искать вызовы методов.
Как уже говорили другие: утверждения не подходят для проверки ввода пользователя.
Если вы обеспокоены многословием, я рекомендую вам проверить библиотеку, которую я написал: https://bitbucket.org/cowwoc/requirements/. Это позволит вам выразить эти проверки, используя очень мало кода, и даже сгенерирует сообщение об ошибке от вашего имени:
requireThat("name", value).isNotNull();
и если вы настаиваете на использовании утверждений, вы можете сделать это тоже:
assertThat("name", value).isNotNull();
Вывод будет выглядеть так:
java.lang.NullPointerException: name may not be null
На самом деле они прибыли в Java 1.4
Я думаю, что основная проблема заключается в том, что когда вы кодируете в среде, где вы сами не управляете опциями jvm, как на серверах eclipse или J2EE (в обоих случаях можно изменить опции jvm, но вам нужно глубоко искать, чтобы найти, где он находится. может быть сделано), проще (я имею в виду, что это требует меньше усилий) использовать if и исключения (или, что еще хуже, ничего не использовать).