Что такое assert java

Assert. Что это?

Assert — это специальная конструкция, позволяющая проверять предположения о значениях произвольных данных в произвольном месте программы. Эта конструкция может автоматически сигнализировать при обнаружении некорректных данных, что обычно приводит к аварийному завершению программы с указанием места обнаружения некорректных данных. Странная, на первый взгляд, конструкция — может завалить программу в самый неподходящий момент. Какой же в ней смысл? Давайте подумаем, что произойдет, если во время исполнения программы в какой-то момент времени некоторые данные программы стали некорректными и мы не «завалили» сразу же программу, а продолжили ее работу, как ни в чем не бывало. Программа может еще долго работать после этого без каких-либо видимых ошибок. А может в любой момент времени в будущем «завалиться» сама по известной только ей причине. Или накачать вам полный винчестер контента с гей-порносайтов. Это называется неопределенное поведение (undefined behavior) и, вопреки расхожему мнению, оно свойственно не только языкам программирования с произвольным доступом к памяти (aka C, C++). Т.к. assert завершает программу сразу же после обнаружения некорректных данных, он позволяет быстро локализировать и исправить баги в программе, которые привели к некорректным данным. Это его основное назначение. Assert’ы доступны во многих языках программирования, включая java, c#, c и python.
Какие виды assert’ов бывают?
Assert’ы позволяют отлавливать ошибки в программах на этапе компиляции либо во время исполнения. Проверки на этапе компиляции не так важны — в большинстве случаев их можно заменить аналогичными проверками во время исполнения программы. Иными словами, assert’ы на этапе компиляции являются ничем иным, как синтаксическим сахаром. Поэтому в дальнейшем под assert’ами будем подразумевать лишь проверки во время исполнения программы.

Важно понимать, что входящие аргументы функции могут быть неявными. Например, при вызове метода класса в функцию неявно передается указатель на объект данного класса (aka this и self). Также функция может обращаться к данным, объявленным в глобальной области видимости, либо к данным из области видимости лексического замыкания. Эти аргументы тоже желательно проверять с помощью assert’ов при входе в функцию.
Если некорректные данные обнаружены на этом этапе, то код данной функции может содержать баги. Пример:

Когда и где стоит использовать assert’ы?
Ответ прост — используйте assert’ы всегда и везде, где они хоть чуточку могут показаться полезными. Ведь они существенно упрощают локализацию багов в коде. Даже проверка результатов выполнения очевидного кода может оказаться полезной при последующем рефакторинге, после которого код может стать не настолько очевидным и в него может запросто закрасться баг. Не бойтесь, что большое количество assert’ов ухудшит ясность кода и замедлит выполнение вашей программы. Assert’ы визуально выделяются из общего кода и несут важную информацию о предположениях, на основе которых работает данный код. Правильно расставленные assert’ы способны заменить большинство комментариев в коде. Большинство языков программирования поддерживают отключение assert’ов либо на этапе компиляции, либо во время выполнения программы, так что они оказывают минимальное влияние на производительность программы. Обычно assert’ы оставляют включенными во время разработки и тестирования программ, но отключают в релиз-версиях программ. Если программа написана в лучших традициях ООП, либо с помощью enterprise методологии, то assert’ы вообще можно не отключать — производительность вряд ли изменится.

Когда можно обойтись без assert’ов?
Понятно, что дублирование assert’ов через каждую строчку кода не сильно улучшит эффективность отлова багов. Не существует единого мнения насчет оптимального количества assert’ов, также как и насчет оптимального количество комментариев в программе. Когда я только узнал про существование assert’ов, мои программы стали содержать 100500 assert’ов, многие из которых многократно дублировали друг друга. С течением времени количество assert’ов в моем коде стало уменьшаться. Следующие правила позволили многократно уменьшить количество assert’ов в моих программах без существенного ухудшения в эффективности отлова багов:
Можно избегать дублирующих проверок входящих аргументов путем размещения их лишь в функциях, непосредственно работающих с данным аргументом. Т.е. если функция foo() не работает с аргументом, а лишь передает его в функцию bar(), то можно опустить проверку этого аргумента в функции foo(), т.к. она продублирована проверкой аргумента в функции bar().
Можно опускать assert’ы на недопустимые значения, которые гарантированно приводят к краху программы в непосредственной близости от данных assert’ов, т.е. если по краху программы можно быстро определить местонахождение бага. К таким assert’ам можно отнести проверки указателя на NULL перед его разыменованием и проверки на нулевое значение делителя перед делением. Еще раз повторюсь — такие проверки можно опускать лишь тогда, когда среда исполнения гарантирует крах программы в данных случаях.
Вполне возможно, что существуют и другие способы, позволяющие уменьшить количество assert’ов без ухудшения эффективности отлова багов. Если вы в курсе этих способов, делитесь ими в комментариях к данному посту.

Когда нельзя использовать assert’ы?
Т.к. assert’ы могут быть удалены на этапе компиляции либо во время исполнения программы, они не должны менять поведение программы. Если в результате удаления assert’а поведение программы может измениться, то это явный признак неправильного использования assert’а. Таким образом, внутри assert’а нельзя вызывать функции, изменяющие состояние программы либо внешнего окружения программы. Например, следующий код неправильно использует assert’ы:

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

Т.к. основное назначение assert’ов — отлов багов (aka ошибки программирования), то они не могут заменить обработку ожидаемых ошибок, которые не являются ошибками программирования. Например:

Если write() возвращает 0, то это вовсе не означает, что в нашей программе есть баг. Если assert’ы в программе будут отключены, то ошибка записи может остаться незамеченной, что впоследствие может привести к печальным результатам. Поэтому assert() тут не подходит. Тут лучше подходит обычная обработка ошибки. Например:

Я программирую на javascript. В нем нет assert’ов. Что мне делать?
В некоторых языках программирования отсутствует явная поддержка assert’ов. При желании они легко могут быть там реализованы, следуя следующему «паттерну проектирования»:

Вообще, assert’ы обычно реализованы в различных фреймворках и библиотеках, предназначенных для автоматизированного тестирования. Иногда они там называются expect’ами. Между автоматизированным тестированием и применением assert’ов есть много общего — обе техники предназначены для быстрого выявления и исправления багов в программах. Но, несмотря на общие черты, автоматизированное тестирование и assert’ы являются не взаимоисключающими, а, скорее всего, взаимодополняющими друг друга. Грамотно расставленные assert’ы упрощают автоматизированное тестирование кода, т.к. тестирующая программа может опустить проверки, дублирующие assert’ы в коде программы. Такие проверки обычно составляют существенную долю всех проверок в тестирующей программе.

Источник

Использование Утверждений Java

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

1. введение

Ключевое слово Java assert позволяет разработчикам быстро проверять определенные предположения или состояние программы.

В этой статье мы рассмотрим, как использовать ключевое слово Java assert .

2. История утверждений Java

Ключевое слово Java assert было введено в Java 1.4, поэтому оно существует уже довольно давно. Тем не менее, это остается малоизвестным ключевым словом, которое может значительно сократить шаблонность и сделать наш код более читабельным.

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

3. Включение утверждений Java

Обратите внимание, что до Java 1.4 Было совершенно законно использовать слово “assert” для именования переменных, методов и т. Д. Это потенциально создает конфликт имен при использовании более старого кода с более новыми версиями JVM.

В этом примере мы включили утверждения для всех классов.

Мы также можем включить утверждения для определенных пакетов и классов:

4. Использование Утверждений Java

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

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

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

5. Обработка ошибки утверждения

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

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

6. Лучшие Практики

Поэтому при использовании утверждений имейте в виду следующее:

7. Заключение

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

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

Источник

Что делает ключевое слово Java assert и когда его следует использовать?

какие-то реальные примеры из жизни чтобы понять ключевую роль утверждения?

17 ответов

утверждения (через утверждаю ключевое слово) были добавлены в Java 1.4. Они используются для проверки правильности инварианта в коде. Они никогда не должны запускаться в производственном коде и указывают на ошибку или неправильное использование пути кода. Они могут быть активированы во время выполнения с помощью на java command, но по умолчанию не включены.

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

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

эта идея основана на оформление по договору (DbC) парадигма: сначала вы определяете (с математической точностью), что должен делать ваш метод, а затем проверяете это с помощью тестирование во время фактического выполнения. Пример:

хотя это довольно очевидно, чтобы работать нормально, большинство программистов не увидят скрытую ошибку внутри этого (подсказка: Ariane V разбился из-за аналогичной ошибки). Теперь DbC определяет, что вы должны всегда проверьте вход и выход функции, чтобы убедиться, что она работает правильно. Java может сделать это через утверждения:

теперь эта функция не подведет, и вы это заметите. Ты узнаешь. что в вашем коде есть проблема, вы знаете, где она находится, и знаете, что ее вызвало (подобно исключениям). И что еще более важно: вы перестаете выполнять правильно, когда это происходит, чтобы предотвратить дальнейшую работу кода с неправильными значениями и потенциально нанести ущерб тому, что он контролирует.

исключения Java-аналогичная концепция, но они не могут проверить все. Если вы хотите еще больше проверок (за счет скорости выполнения), вы должны использовать утверждения. Это коптит ваш код, но вы можете в конце концов доставить продукт в удивительно короткое время разработки (чем раньше вы исправите ошибку, тем ниже стоимость). И кроме того: если в вашем коде есть какая-либо ошибка, Вы ее обнаружите. Нет никакого способа проскальзывания ошибки и вызвать проблемы позже.

Это еще не гарантия для кода без ошибок, но это намного ближе к этому, чем обычные программы.

утверждения являются инструментом фазы разработки, чтобы поймать ошибки в коде. Они предназначены для легкого удаления, поэтому они не будут существовать в производственном коде. Таким образом, утверждения не являются частью «решения», которое вы предоставляете клиенту. Это внутренние проверки, чтобы убедиться, что ваши предположения верны. Самым распространенным примером является проверка на null. Многие методы написаны так:

очень часто в таком методе виджет просто никогда не должен иметь значение null. Поэтому, если это null, в вашем коде есть ошибка, которую вам нужно отследить. Но приведенный выше код никогда не скажет вам этого. Таким образом, в благих намерениях, чтобы написать «безопасный» код, вы также скрываете ошибку. Гораздо лучше написать такой код:

таким образом, вы будете уверены, чтобы поймать этот баг раньше. (Также полезно указать в контракте, что этот параметр никогда не должен быть нулевым.) Обязательно включите утверждения при тестировании кода во время развитие. (И убедить ваших коллег сделать это тоже часто бывает трудно, что меня очень раздражает.)

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

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

вот реальный пример: я однажды написал метод, который сравнивал два произвольных значения для равенства, где любое значение может быть null:

этот код делегирует работу equals() метод в случае, когда это значение не null. Но это предполагает equals() метод правильно выполняет контракт equals() путем правильной обработки параметра null.

коллега возразил против моего кода, говоришь мне, что многие из наших классов багги equals() методы, которые не тестируются на null, поэтому я должен поместить эту проверку в этот метод. Это спорно, если это разумно, или если мы должны заставить ошибку, чтобы мы могли ее обнаружить и исправить, но я уступил своему коллеге и поставил нулевую проверку, которую я отметил комментарием:

equals() правильно, поэтому я могу это исправить:

важными моментами, которые следует иметь в виду, являются следующие:

утверждения являются инструментами фазы разработки только.

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

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

утверждения не изменяют поведение кода в производстве, поэтому мой коллега рад, что проверка null существует, и что этот метод будет выполняться правильно, даже если equals() метод багги. Я счастлив, потому что я поймаю любой багги equals() метод в развитии.

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

много хороших ответов, пояснив, что assert ключевое слово, но мало кто отвечает на вопрос, «когда же assert ключевое слово будет использоваться в реальной жизни?»

ответ: почти никогда не.

движущая идея за assert ключевое слово-преждевременная оптимизация, и основная функция-возможность легко отключить все проверки. На самом деле, assert проверки по умолчанию отключены.

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

иногда может возникнуть соблазн написать инвариантную проверку, которая занимает нежелательно много времени для обработки (и вызывается достаточно часто, чтобы это имело значение). Однако такие проверки замедлят тестирование, что также нежелательно. Такие трудоемкие проверки обычно записываются в виде модульных тестов. Тем не менее, иногда может иметь смысл использовать assert по этому поводу.

(Rant: разработчики JVM были кучей ужасных, преждевременно оптимизирующих кодеров. Вот почему вы слышите о стольких проблемах безопасности в плагине Java и JVM. Они отказались включить в производственный код базовые проверки и утверждения, и мы продолжаем платить цену.)

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

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

утверждения используются для проверки пост-условий и» никогда не должны терпеть неудачу » предварительные условия. Правильный код никогда не должен ошибаться в утверждении; когда они срабатывают, они должны указывать на ошибку (надеюсь, в месте, близком к тому, где находится фактический локус проблемы).

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

что делает ключевое слово assert в Java?

давайте посмотрим на скомпилированный байт-код.

генерирует почти тот же байт-код, что и:

мы используем: System.currentTimeMillis() чтобы убедиться, что он не будет оптимизировать ( assert true; делавший.)

синтетическое поле генерируется так, что Java нужно только вызвать Assert.class.desiredAssertionStatus() один раз во время загрузки, а затем кэширует результат есть. См. также: что означает «статический синтетический»?

мы можем проверить это с помощью:

С Oracle JDK 1.8.0_45 было создано синтетическое статическое поле (см. Также:что означает «статический синтетический»?):

Источник

Programming With Assertions

An assertion is a statement in the Java TM programming language that enables you to test your assumptions about your program. For example, if you write a method that calculates the speed of a particle, you might assert that the calculated speed is less than the speed of light.

Each assertion contains a boolean expression that you believe will be true when the assertion executes. If it is not true, the system will throw an error. By verifying that the boolean expression is indeed true, the assertion confirms your assumptions about the behavior of your program, increasing your confidence that the program is free of errors.

Experience has shown that writing assertions while programming is one of the quickest and most effective ways to detect and correct bugs. As an added benefit, assertions serve to document the inner workings of your program, enhancing maintainability.

This document shows you how to program with assertions. It covers the topics:

Introduction

The assertion statement has two forms. The first, simpler form is:

where Expression 1 is a boolean expression. When the system runs the assertion, it evaluates Expression 1 and if it is false throws an AssertionError with no detail message.

The second form of the assertion statement is:

The purpose of the detail message is to capture and communicate the details of the assertion failure. The message should allow you to diagnose and ultimately fix the error that led the assertion to fail. Note that the detail message is not a user-level error message, so it is generally unnecessary to make these messages understandable in isolation, or to internationalize them. The detail message is meant to be interpreted in the context of a full stack trace, in conjunction with the source code containing the failed assertion.

In some cases Expression 1 may be expensive to evaluate. For example, suppose you write a method to find the minimum element in an unsorted list, and you add an assertion to verify that the selected element is indeed the minimum. The work done by the assert will be at least as expensive as the work done by the method itself. To ensure that assertions are not a performance liability in deployed applications, assertions can be enabled or disabled when the program is started, and are disabled by default. Disabling assertions eliminates their performance penalty entirely. Once disabled, they are essentially equivalent to empty statements in semantics and performance. See Enabling and Disabling Assertions for more information.

The addition of the assert keyword to the Java programming language has implications for existing code. See Compatibility With Existing Programs for more information.

Putting Assertions Into Your Code

There are many situations where it is good to use assertions, including:

There are also situations where you should not use them:

The program would work fine when asserts were enabled, but would fail when they were disabled, as it would no longer remove the null elements from the list. The correct idiom is to perform the action before the assertion and then assert that the action succeeded:

As a rule, the expressions contained in assertions should be free of side effects: evaluating the expression should not affect any state that is visible after the evaluation is complete. One exception to this rule is that assertions can modify state that is used only from within other assertions. An idiom that makes use of this exception is presented later in this document.

Internal Invariants

Before assertions were available, many programmers used comments to indicate their assumptions concerning a program’s behavior. For example, you might have written something like this to explain your assumption about an else clause in a multiway if-statement:

You should now use an assertion whenever you would have written a comment that asserts an invariant. For example, you should rewrite the previous if-statement like this:

Note, incidentally, that the assertion in the above example may fail if i is negative, as the % operator is not a true modulus operator, but computes the remainder, which may be negative.

Another good candidate for an assertion is a switch statement with no default case. The absence of a default case typically indicates that a programmer believes that one of the cases will always be executed. The assumption that a particular variable will have one of a small number of values is an invariant that should be checked with an assertion. For example, suppose the following switch statement appears in a program that handles playing cards:

It probably indicates an assumption that the suit variable will have one of only four values. To test this assumption, you should add the following default case:

If the suit variable takes on another value and assertions are enabled, the assert will fail and an AssertionError will be thrown.

An acceptable alternative is:

This alternative offers protection even if assertions are disabled, but the extra protection adds no cost: the throw statement won’t execute unless the program has failed. Moreover, the alternative is legal under some circumstances where the assert statement is not. If the enclosing method returns a value, each case in the switch statement contains a return statement, and no return statement follows the switch statement, then it would cause a syntax error to add a default case with an assertion. (The method would return without a value if no case matched and assertions were disabled.)

Control-Flow Invariants

The previous example not only tests an invariant, it also checks an assumption about the application’s flow of control. The author of the original switch statement probably assumed not only that the suit variable would always have one of four values, but also that one of the four cases would always be executed. It points out another general area where you should use assertions: place an assertion at any location you assume will not be reached. The assertions statement to use is:

For example, suppose you have a method that looks like this:

Replace the final comment so that the code now reads:

Preconditions, Postconditions, and Class Invariants

While the assert construct is not a full-blown design-by-contract facility, it can help support an informal design-by-contract style of programming. This section shows you how to use asserts for:

Preconditions

By convention, preconditions on public methods are enforced by explicit checks that throw particular, specified exceptions. For example:

You can, however, use an assertion to test a nonpublic method’s precondition that you believe will be true no matter what a client does with the class. For example, an assertion is appropriate in the following «helper method» that is invoked by the previous method:

Note, the above assertion will fail if MAX_REFRESH_RATE is greater than 1000 and the client selects a refresh rate greater than 1000. This would, in fact, indicate a bug in the library!

Lock-Status Preconditions

Classes designed for multithreaded use often have non-public methods with preconditions relating to whether or not some lock is held. For example, it is not uncommon to see something like this:

A static method called holdsLock has been added to the Thread class to test whether the current thread holds the lock on a specified object. This method can be used in combination with an assert statement to supplement a comment describing a lock-status precondition, as shown in the following example:

Note that it is also possible to write a lock-status assertion asserting that a given lock isn’t held.

Postconditions

You can test postcondition with assertions in both public and nonpublic methods. For example, the following public method uses an assert statement to check a post condition:

Occasionally it is necessary to save some data prior to performing a computation in order to check a postcondition. You can do this with two assert statements and a simple inner class that saves the state of one or more variables so they can be checked (or rechecked) after the computation. For example, suppose you have a piece of code that looks like this:

Here is how you could modify the above method to turn the textual assertion of a postcondition into a functional one:

You can easily generalize this idiom to save more than one data field, and to test arbitrarily complex assertions concerning pre-computation and post-computation values.

You might be tempted to replace the first assert statement (which is executed solely for its side-effect) by the following, more expressive statement:

Don’t make this replacement. The statement above would copy the array whether or not asserts were enabled, violating the principle that assertions should have no cost when disabled.

Class Invariants

A class invariant is a type of internal invariant that applies to every instance of a class at all times, except when an instance is in transition from one consistent state to another. A class invariant can specify the relationships among multiple attributes, and should be true before and after any method completes. For example, suppose you implement a balanced tree data structure of some sort. A class invariant might be that the tree is balanced and properly ordered.

The assertion mechanism does not enforce any particular style for checking invariants. It is sometimes convenient, though, to combine the expressions that check required constraints into a single internal method that can be called by assertions. Continuing the balanced tree example, it might be appropriate to implement a private method that checked that the tree was indeed balanced as per the dictates of the data structure:

Because this method checks a constraint that should be true before and after any method completes, each public method and constructor should contain the following line immediately prior to its return:

It is generally unnecessary to place similar checks at the head of each public method unless the data structure is implemented by native methods. In this case, it is possible that a memory corruption bug could corrupt a «native peer» data structure in between method invocations. A failure of the assertion at the head of such a method would indicate that such memory corruption had occurred. Similarly, it may be advisable to include class invariant checks at the heads of methods in classes whose state is modifiable by other classes. (Better yet, design classes so that their state is not directly visible to other classes!)

Advanced Uses

The following sections discuss topics that apply only to resource-constrained devices and to systems where asserts must not be disabled in the field. If you have no interest in these topics, skip to the next section, «Compiling Files that Use Assertions».

Removing all Trace of Assertions from Class Files

Programmers developing applications for resource-constrained devices may wish to strip assertions out of class files entirely. While this makes it impossible to enable assertions in the field, it also reduces class file size, possibly leading to improved class loading performance. In the absence of a high quality JIT, it could lead to decreased footprint and improved runtime performance.

The assertion facility offers no direct support for stripping assertions out of class files. The assert statement may, however, be used in conjunction with the «conditional compilation» idiom described in the Java Language Specification, enabling the compiler to eliminate all traces of these asserts from the class files that it generates:

Requiring that Assertions are Enabled

Programmers of certain critical systems might wish to ensure that assertions are not disabled in the field. The following static initialization idiom prevents a class from being initialized if its assertions have been disabled:

Put this static-initializer at the top of your class.

Compiling Files That Use Assertions

This flag is necessary so as not to cause source compatibility problems.

Enabling and Disabling Assertions

By default, assertions are disabled at runtime. Two command-line switches allow you to selectively enable or disable assertions.

If a single command line contains multiple instances of these switches, they are processed in order before loading any classes. For example, the following command runs the BatTutor program with assertions enabled in package com.wombat.fruitbat but disabled in class com.wombat.fruitbat.Brickbat :

The above switches apply to all class loaders. With one exception, they also apply to system classes (which do not have an explicit class loader). The exception concerns the switches with no arguments, which (as indicated above) do not apply to system classes.This behavior makes it easy to enable asserts in all classes except for system classes, which is commonly desirable.

For example, the following command runs the BatTutor program with assertions enabled in system classes, as well as in the com.wombat.fruitbat package and its subpackages:

The assertion status of a class (enabled or disabled) is set at the time it is initialized, and does not change. There is, however, one corner case that demands special treatment. It is possible, though generally not desirable, to execute methods or constructors prior to initialization. This can happen when a class hierarchy contains a circularity in its static initialization.

If an assert statement executes before its class is initialized, the execution must behave as if assertions were enabled in the class. This topic is discussed in detail in the assertions specification in the Java Language Specification.

Compatibility With Existing Programs

Design FAQ

Here is a collection of frequently asked questions concerning the design of the assertion facility.

General Questions

Although ad hoc implementations are possible, they are of necessity either ugly (requiring an if statement for each assertion) or inefficient (evaluating the condition even if assertions are disabled). Further, each ad hoc implementation has its own means of enabling and disabling assertions, which lessens the utility of these implementations, especially for debugging in the field. As a result of these shortcomings, assertions have never become a part of the culture among engineers using the Java programming language. Adding assertion support to the platform stands a good chance of rectifying this situation.

We recognize that a language change is a serious effort, not to be undertaken lightly. The library approach was considered. It was, however, deemed essential that the runtime cost of assertions be negligible if they are disabled. In order to achieve this with a library, the programmer is forced to hard-code each assertion as an if statement. Many programmers would not do this. Either they would omit the if statement and performance would suffer, or they would ignore the facility entirely. Note also that assertions were contained in James Gosling’s original specification for the Java programming language. Assertions were removed from the Oak specification because time constraints prevented a satisfactory design and implementation.

We considered providing such a facility, but were unable to convince ourselves that it is possible to graft it onto the Java programming language without massive changes to the Java platform libraries, and massive inconsistencies between old and new libraries. Further, we were not convinced that such a facility would preserve the simplicity that is the hallmark of the Java programming language. On balance, we came to the conclusion that a simple boolean assertion facility was a fairly straight-forward solution and far less risky. It’s worth noting that adding a boolean assertion facility to the language doesn’t preclude adding a full-fledged design-by-contract facility at some time in the future.

Providing such a construct would encourage programmers to put complex assertions inline, when they are better relegated to separate methods.

Compatibility

Yes, for source files. (Binaries for classes that use assert as an identifier will continue to work fine.) To ease the transition, we implemented a strategy whereby developers can continue using assert as an identifier during a transitional period.

Yes. Class files will contain calls to the new ClassLoader and Class methods, such as desiredAssertionStatus. If a class file containing calls to these methods is run against an older JRE (whose ClassLoader class doesn’t define the methods), the program will fail at run time, throwing a NoSuchMethodError. It is generally the case that programs using new facilities are not compatible with older releases.

Syntax and Semantics

The AssertionError Class

Access to these objects would encourage programmers to attempt to recover from assertion failures, which defeats the purpose of the facility.

This issue was controversial. The expert group discussed it at length, and came to the conclusion that Error was more appropriate to discourage programmers from attempting to recover from assertion failures. It is, in general, difficult or impossible to localize the source of an assertion failure. Such a failure indicates that the program is operating «outside of known space,» and attempts to continue execution are likely to be harmful. Further, convention dictates that methods specify most runtime exceptions they may throw (with @throws doc comments). It makes little sense to include in a method’s specification the circumstances under which it may generate an assertion failure. Such information may be regarded as an implementation detail, which can change from implementation to implementation and release to release.

Enabling and Disabling Assertions

It is a firm requirement that it be possible to enable assertions in the field, for enhanced serviceability. It would have been possible to also permit developers to eliminate assertions from object files at compile time. Assertions can contain side effects, though they should not, and such a flag could therefore alter the behavior of a program in significant ways. It is viewed as good thing that there is only one semantics associated with each valid Java program. Also, we want to encourage users to leave asserts in object files so they can be enabled in the field. Finally, the spec demands that assertions behave as if enabled when a class runs before it is initialized. It would be impossible to offer these semantics if assertions were stripped from the class file. Note, however, that the standard «conditional compilation idiom» described in the Java Language Specification can be used to achieve this effect for developers who really want it.

Hierarchical control is useful, as programmers really do use package hierarchies to organize their code. For example, package-tree semantics allow assertions to be enabled or disabled in all of Swing at one time.

No action (other than perhaps a warning message) is necessary or desirable if it’s too late to set the assertion status. An exception seems unduly heavyweight.

Clarity in method naming is for the greater good. Overloading tends to cause confusion.

It’s not clear that there would be any use for the resulting method. The method isn’t designed for application programmer use, and it seems inadvisable to make it slower and more complex than necessary.

While applets have no reason to call any of the ClassLoader methods for modifying assertion status, allowing them to do so seems harmless. At worst, an applet can mount a weak denial-of-service attack by enabling assertions in classes that have yet to be initialized. Moreover, applets can only affect the assert status of classes that are to be loaded by class loaders that the applets can access. There already exists a RuntimePermission to prevent untrusted code from gaining access to class loaders ( getClassLoader ).

Such a construct would encourage people to inline complex assertion code, which we view as a bad thing. Further, it is straightforward to query the assert status atop the current API, if you feel you must:

Few programmers are aware of the fact that a class’s constructors and methods can run prior to its initialization. When this happens, it is quite likely that the class’s invariants have not yet been established, which can cause serious and subtle bugs. Any assertion that executes in this state is likely to fail, alerting the programmer to the problem. Thus, it is generally helpful to the programmer to execute all assertions encountered while in this state.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *