Утверждения Java недостаточно используются - PullRequest
65 голосов
/ 18 ноября 2008

Мне интересно, почему ключевое слово assert так мало используется в Java? Я почти никогда не видел, чтобы они использовались, но я думаю, что они отличная идея. Я определенно предпочитаю краткость:

assert param != null : "Param cannot be null";

к многословию:

if (param == null) {
    throw new IllegalArgumentException("Param cannot be null");
}

Я подозреваю, что они недостаточно используются, потому что

  • Они прибыли относительно поздно (Java 1.4), к тому времени многие люди уже установили свой стиль / привычку программирования на Java
  • По умолчанию они отключены во время выполнения

Ответы [ 11 ]

62 голосов
/ 18 ноября 2008

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

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

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

Ваше мнение о том, что они "опаздывают" на java, также является причиной, по которой их не так широко видели.

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

56 голосов
/ 18 ноября 2008

Это злоупотребление утверждениями, чтобы использовать их для проверки ввода пользователя. Бросок IllegalArgumentException на неверный ввод является более правильным, поскольку он позволяет вызывающему методу перехватить исключение, отобразить ошибку и сделать все, что нужно (запросить ввод еще раз, выйти, что угодно).

Если этот метод является закрытым методом внутри одного из ваших классов, утверждение в порядке, потому что вы просто пытаетесь убедиться, что случайно не передали ему нулевой аргумент. Вы проверяете с включенными утверждениями, и когда вы проверили все пути, не пройдя утверждение, вы можете отключить их, чтобы не тратить на них ресурсы. Они также полезны как комментарии. assert в начале метода является хорошей документацией для сопровождающих, что они должны следовать определенным предварительным условиям, а assert в конце с постусловием документирует, что должен делать метод. Они могут быть так же полезны, как комментарии; более того, потому что с утверждениями они фактически проверяют то, что документируют.

Утверждения предназначены для тестирования / отладки, а не для проверки ошибок, поэтому они по умолчанию отключены: чтобы люди не использовали утверждения для проверки ввода пользователя.

19 голосов
/ 18 ноября 2008

С Программирование с утверждениями

По умолчанию утверждения отключены во время выполнения. Два параметра командной строки позволяют выборочно включать или отключать утверждения.

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

18 голосов
/ 18 ноября 2008

В «Эффективной Java» Джошуа Блох предложил (в теме «Проверка параметров на достоверность»), что (вроде как простое правило для принятия), для открытых методов, мы проверим аргументы и сгенерируем необходимое исключение, если оно найдено недопустимо, и для непубличных методов (которые не предоставляются, и вы, как пользователь их, должны обеспечить их действительность), мы можем использовать утверждение вместо этого.

Ус

9 голосов
/ 20 марта 2009

@ Дон, вы разочарованы тем, что утверждение по умолчанию отключено. Я также, и, таким образом, написал этот маленький плагин javac, который вставляет их (т.е. испускает байт-код для if (!expr) throw Ex, а не этот глупый байт-код assert.

Если вы включите fa.jar в ваш путь к классам при компиляции кода Java, он сделает свое дело и затем скажет

Note: %n assertions inlined.

@ см. http://smallwiki.unibe.ch/adriankuhn/javacompiler/forceassertions и, альтернативно, на github https://github.com/akuhn/javac

2 голосов
/ 29 июля 2013

Утверждения полезны, потому что они:

  • ловить ошибки ПРОГРАММИРОВАНИЯ рано
  • код документа с использованием кода

Думайте о них как о самопроверке кода. Если они терпят неудачу, это должно означать, что ваша программа сломана и должна остановиться. Всегда включайте их во время модульного тестирования!

In Прагматичный программист они даже рекомендуют разрешить им запускаться в производство.

Оставить утверждения включенными

Используйте утверждения, чтобы предотвратить невозможное.

Обратите внимание, что утверждения выдают AssertionError, если они терпят неудачу, поэтому не перехватываются исключением catch.

2 голосов
/ 09 ноября 2009

Я не уверен, почему вы потрудитесь написать утверждения, а затем заменить их стандартным условием if then, почему бы просто не написать условия, как будто, во-первых?

Утверждения предназначены только для тестирования и имеют два побочных эффекта: увеличение двоичных файлов и снижение производительности при включении (поэтому вы можете их отключить!)

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

1 голос
/ 18 ноября 2008

Утверждения очень ограничены: вы можете тестировать только логические условия, и вам нужно каждый раз писать код для полезного сообщения об ошибке. Сравните это с assertEquals () JUnit, который позволяет генерировать полезное сообщение об ошибке из входов и даже отображать два входа рядом в IDE в среде выполнения JUnit.

Кроме того, вы не можете искать утверждения в любой IDE, которую я видел до сих пор, но каждая IDE может искать вызовы методов.

0 голосов
/ 20 февраля 2019

ТЛ; др

  • Да, используйте тестирование утверждений в производстве , где это имеет смысл.
  • Используйте другие библиотеки ( JUnit , AssertJ , Hamcrest и т. Д. .) вместо встроенного assert объекта, если хотите.

Большинство других Ответов на этой странице выдвигают максиму «Утверждения, как правило, не используются в производственном коде». Хотя это верно в приложениях для повышения производительности, таких как текстовый процессор или электронная таблица, в пользовательских бизнес-приложениях, где так широко используется Java Тестирование утверждений на производстве чрезвычайно полезно и распространено.

Как и многие максимы в мире программирования, то, что начинается с истины в одном контексте, неправильно истолковывается, а затем неправильно применяется в других контекстах.

Приложения для повышения производительности

Этот принцип «Утверждения, как правило, не используются в производственном коде», хотя и распространен, неверен.

Формализованное тестирование утверждений, созданное с помощью таких приложений, как текстовый процессор, например Microsoft Word , или электронной таблицы, например Microsoft Excel . Эти приложения могут вызывать массив подтверждений проверок утверждений при каждом нажатии клавиши , сделанной пользователем. Такое экстремальное повторение сильно повлияло на производительность. Таким образом, только бета-версии таких продуктов в ограниченном выпуске имели включенные утверждения. Таким образом, максим.

Бизнес-приложения

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

Проверка бизнес-правил

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

Условия выполнения

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

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

Sanity-чека

Проверка работоспособности во время выполнения в производстве также вполне разумна и должна поощряться. Тестирование нескольких произвольных условий, которые невозможно представить себе как неправду, спасло мой бекон в бесчисленных ситуациях, когда происходило какое-то странное событие.

Например, тестирование того, что округление никеля (0,05) до пенни привело к получению никеля (0,05) в определенной библиотеке, помогло мне стать одним из первых, кто обнаружил недостаток технологии с плавающей запятой, который Apple выпустила в их Библиотека Rosetta при переходе с PowerPC на Intel. Такой недостаток, достигающий публики, казался бы невозможным. Но, что удивительно, этот недостаток ускользнул от внимания первоначального поставщика, Transitive и Apple, а также разработчиков раннего доступа, тестировавших бета-версии Apple.

(Кстати, я должен упомянуть ... никогда не использовать с плавающей точкой для денег , использовать BigDecimal.)

Выбор рамок

Вместо того, чтобы использовать встроенное средство assert, вы можете рассмотреть возможность использования другой платформы утверждений. У вас есть несколько вариантов, в том числе:

Или гОЛЛ своего собственного. Сделайте небольшой класс для использования в вашем проекте. Как то так.

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

0 голосов
/ 06 апреля 2017

Как уже говорили другие: утверждения не подходят для проверки ввода пользователя.

Если вы обеспокоены многословием, я рекомендую вам проверить библиотеку, которую я написал: https://bitbucket.org/cowwoc/requirements/. Это позволит вам выразить эти проверки с использованием очень небольшого кода и даже сгенерирует сообщение об ошибке на Ваше имя:

requireThat("name", value).isNotNull();

и если вы настаиваете на использовании утверждений, вы также можете сделать это:

assertThat("name", value).isNotNull();

Вывод будет выглядеть так:

java.lang.NullPointerException: name may not be null
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...