Spec-Zone .ru
спецификации, руководства, описания, API
|
Утверждение является оператором в языке программирования JavaTM, который позволяет Вам протестировать свои предположения о Вашей программе. Например, если Вы пишете метод, который вычисляет скорость частицы, Вы могли бы утверждать, что расчетная скорость является меньше чем скорость света.
Каждое утверждение содержит булево выражение, которому Вы верите, будет истина, когда утверждение выполняется. Если это не будет истина, то система бросит ошибку. Проверяя, что булево выражение является действительно истиной, утверждение подтверждает Ваши предположения о поведении Вашей программы, увеличивая Вашу уверенность, что программа является бесплатной от ошибок.
Опыт показал, что запись утверждений, в то время как программирование является одним из самых быстрых и самых эффективных способов обнаружить и исправить ошибки. Как дополнительное преимущество, утверждения служат, чтобы задокументировать внутренние работы Вашей программы, улучшая пригодность для обслуживания.
Этот документ показывает Вам, как программировать с утверждениями. Это затрагивает темы:
У оператора контроля есть две формы. Первая, более простая форма:
assert Expression1 ;
где Expression1 является a boolean
выражение. Когда система выполняет утверждение, она оценивает Expression1 и если это false
броски AssertionError
без сообщения детали.
Вторая форма оператора контроля:
assert Expression1 : Expression2 ;
где:
void
.)Используйте эту версию assert
оператор, чтобы обеспечить деталь обменивается сообщениями для AssertionError
. Система передает значение Expression2 к соответствующему AssertionError
конструктор, который использует строковое представление значения как сообщение детали ошибки.
Цель сообщения детали состоит в том, чтобы получить и передать детали отказа утверждения. Сообщение должно позволить Вам диагностировать и в конечном счете фиксировать ошибку, которая привела утверждение перестать работать. Отметьте, что сообщение детали не является сообщением об ошибке на уровне пользователя, таким образом, является обычно ненужным сделать эти сообщения понятными в изоляции, или интернационализировать их. Сообщение детали предназначается, чтобы быть интерпретированным в контексте полной трассировки стека в соединении с исходным кодом, содержащим отказавшее утверждение.
Как все непойманные исключения, отказы утверждения обычно маркируются в трассировке стека с файлом и номером строки, от которого они были брошены. Вторая форма оператора контроля должна использоваться в предпочтении к первому только, когда у программы есть некоторая дополнительная информация, которая могла бы помочь диагностировать отказ. Например, если Expression1 включает отношение между двумя переменными x
и y
, вторая форма должна использоваться. При этих обстоятельствах разумный кандидат на Expression2 был бы "x: " + x + ", y: " + y
.
В некоторых случаях Expression1 может быть дорогим, чтобы оценить. Например, предположите, что Вы пишете метод, чтобы найти минимальный элемент в несортированном списке, и Вы добавляете утверждение, чтобы проверить, что выбранный элемент является действительно минимумом. Работа, сделанная утверждением, будет, по крайней мере, столь же дорога как работа, сделанная методом непосредственно. Чтобы гарантировать, что утверждения не являются ответственностью производительности в развернутых приложениях, утверждения могут быть включены или отключены, когда программа запускается, и отключается по умолчанию. Отключение утверждений устраняет их потерю производительности полностью. После того, как отключенный, они чрезвычайно эквивалентны пустым операторам в семантике и производительности. См. Включение и Отключение Утверждений для получения дополнительной информации.
Добавление assert
у ключевого слова к языку программирования Java есть импликации для существующего кода. См. Совместимость С Существующими Программами для получения дополнительной информации.
Есть много ситуаций, где хорошо использовать утверждения, включая:
Есть также ситуации, где недопустимо использовать их:
Проверка параметра обычно является частью опубликованных спецификаций (или контракт) метода, и этим спецификациям нужно повиноваться, включаются ли утверждения или отключаются. Другая проблема с использованием утверждений для проверки параметра состоит в том, что ошибочные параметры должны привести к соответствующему исключению на этапе выполнения (такой как IllegalArgumentException
, IndexOutOfBoundsException
, или NullPointerException
). Отказ утверждения не будет выдавать соответствующее исключение.
Поскольку утверждения могут быть отключены, программы не должны предположить, что булево выражение, содержавшееся в утверждении, будет оценено. У нарушения этого правила есть страшные последствия. Например, предположите, что Вы хотели удалить все нулевые элементы от списка names
, и знал, что список содержавший или больше обнуляют. Было бы неправильно сделать это:
// Broken! - action is contained in assertion assert names.remove(null);
Программа хорошо работала бы, когда утверждает, были включены, но перестанет работать, когда они были отключены, поскольку она больше не будет удалять нулевые элементы из списка. Корректная идиома должна выполнить действие перед утверждением и затем утверждать что действие, за которым следуют:
// Fixed - action precedes assertion boolean nullsRemoved = names.remove(null); assert nullsRemoved; // Runs whether or not asserts are enabled
Как правило выражения, содержавшиеся в утверждениях, должны быть свободными от побочных эффектов: оценка выражения не должна влиять ни на какое состояние, которое видимо после того, как оценка полна. Одно исключение к этому правилу - то, что утверждения могут изменить состояние, которое используется только изнутри других утверждений. Идиома, которая использует это исключение, представляется позже в этом документе.
Прежде, чем утверждения были доступны, много программистов используемые комментарии, чтобы указать на их предположения относительно поведения программы. Например, Вы, возможно, записали что-то вроде этого, чтобы объяснить Ваше предположение о else
пункт в многоканальном операторе "if":
if (i % 3 == 0) { ... } else if (i % 3 == 1) { ... } else { // We know (i % 3 == 2) ... }
Следует теперь использовать утверждение всякий раз, когда Вы записали бы комментарий, который утверждает инвариант. Например, следует переписать предыдущий оператор "if" как это:
if (i % 3 == 0) { ... } else if (i % 3 == 1) { ... } else { assert i % 3 == 2 : i; ... }
Отметьте, случайно, что утверждение в вышеупомянутом примере может перестать работать если i
отрицательно, как %
оператор не является истинным оператором модуля, но вычисляет остаток, который может быть отрицательным.
Другой хороший кандидат на утверждение является a switch
оператор без default
случай. Отсутствие a default
случай обычно указывает, что программист полагает, что один из случаев будет всегда выполняться. Предположение, что у определенной переменной будет одно из небольшого количества значений, является инвариантом, который должен быть проверен с утверждением. Например, предположите следующий switch
оператор появляется в программе, которая обрабатывает игру в карты:
switch(suit) { case Suit.CLUBS: ... break; case Suit.DIAMONDS: ... break; case Suit.HEARTS: ... break; case Suit.SPADES: ... }
Это, вероятно, указывает на предположение что suit
у переменной будет одно только из четырех значений. Чтобы протестировать это предположение, следует добавить следующий случай значения по умолчанию:
default: assert false : suit;
Если suit
переменная берет другое значение, и утверждения включаются, утверждение перестанет работать и AssertionError
будет брошен.
Приемлемая альтернатива:
default: throw new AssertionError(suit);
Эта альтернатива предлагает защиту, даже если утверждения отключаются, но дополнительная защита не добавляет стоимости: throw
оператор не будет выполняться, если программа не перестала работать. Кроме того альтернатива является законной при некоторых обстоятельствах где assert
оператор не. Если метод включения возвращает значение, каждый случай в switch
оператор содержит a return
оператор, и нет return
оператор следует switch
оператор, тогда это вызвало бы синтаксическую ошибку добавить случай значения по умолчанию с утверждением. (Метод возвратился бы без значения, если бы никакой соответствующий случай и утверждения не был отключен.)
Предыдущий пример не только тестирует инвариант, он также проверяет предположение о потоке приложения управления. Автор оригинала switch
оператор, вероятно, принятый не только, что suit
у переменной всегда было бы одно из четырех значений, но также и что один из этих четырех случаев будет всегда выполняться. Это указывает на другую общую область, где следует использовать утверждения: поместите утверждение в любое расположение, которое Вы принимаете, не будет достигнут. Оператор утверждений, чтобы использовать:
assert false;
Например, предположите, что у Вас есть метод, который похож на это:
void foo() { for (...) { if (...) return; } // Execution should never reach this point!!! }
Замените заключительный комментарий так, чтобы код теперь читал:
void foo() { for (...) { if (...) return; } assert false; // Execution should never reach this point! }
Отметьте: Используйте этот метод с усмотрением. Если оператор будет недостижим как определено в Спецификации языка Java, то Вы получите ошибку времени компиляции, если Вы попытаетесь утверждать, что это не достигается. Снова, приемлемая альтернатива должна просто бросить AssertionError
.
В то время как утверждать конструкция не является распустившимся средством проекта согласно контракту, она может помочь поддержать неофициальный стиль проекта согласно контракту программирования. Этот раздел показывает Вам, как использовать, утверждает для:
Условно, предварительные условия на открытых методах осуществляются явными проверками, которые выдают определенные, указанные исключения. Например:
/** * Sets the refresh rate. * * @param rate refresh rate, in frames per second. * @throws IllegalArgumentException if rate <= 0 or * rate > MAX_REFRESH_RATE. */ public void setRefreshRate(int rate) { // Enforce specified precondition in public method if (rate <= 0 || rate > MAX_REFRESH_RATE) throw new IllegalArgumentException("Illegal rate: " + rate); setRefreshInterval(1000/rate); }
Это соглашение незатронуто добавлением assert
создать. Не используйте утверждения, чтобы проверить параметры открытого метода. Утверждение является несоответствующим, потому что метод гарантирует, что это будет всегда осуществлять проверки параметра. Это должно проверить свои параметры, включаются ли утверждения. Далее, assert
конструкция не выдает исключение указанного типа. Это может бросить только AssertionError
.
Можно, однако, использовать утверждение, чтобы протестировать предварительное условие непубличного метода, которому Вы верите, будет истина независимо от того, что клиент делает с class. Например, утверждение является соответствующим в следующем "методе помощника", который вызывается предыдущим методом:
/** * Sets the refresh interval (which must correspond to a legal frame rate). * * @param interval refresh interval in milliseconds. */ private void setRefreshInterval(int interval) { // Confirm adherence to precondition in nonpublic method assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE : interval; ... // Set the refresh interval }
Отметьте, вышеупомянутое утверждение перестанет работать если MAX_REFRESH_RATE
больше чем 1000, и клиент выбирает частоту обновления, больше чем 1000. Это, фактически, указало бы на ошибку в библиотеке!
У классов, разработанных для многопоточного использования часто, есть непубличные методы с предварительными условиями, касающимися, сохранена ли некоторая блокировка. Например, весьма распространено видеть что-то вроде этого:
private Object[] a; public synchronized int find(Object key) { return find(key, a, 0, a.length); } // Recursive helper method - always called with a lock on this object private int find(Object key, Object[] arr, int start, int len) { ... }
Вызывают статический метод holdsLock
был добавлен к Thread
class, чтобы протестировать, содержит ли текущий поток блокировку на указанном объекте. Этот метод может использоваться в комбинации с assert
оператор, чтобы добавить комментарий, описывающий предварительное условие состояния блокировки, как показано в следующем примере:
// Recursive helper method - always called with a lock on this. private int find(Object key, Object[] arr, int start, int len) { assert Thread.holdsLock(this); // lock-status assertion ... }
Отметьте, что также возможно записать утверждение состояния блокировки, утверждая, что данная блокировка не сохранена.
Можно протестировать постусловие с утверждениями и в общедоступных и в непубличных методах. Например, следующий открытый метод использует assert
оператор, чтобы проверить условие сообщения:
/** * Returns a BigInteger whose value is (this-1 mod m). * * @param m the modulus. * @return this-1 mod m. * @throws ArithmeticException m <= 0, or this BigInteger *has no multiplicative inverse mod m (that is, this BigInteger *is not relatively prime to m). */ public BigInteger modInverse(BigInteger m) { if (m.signum <= 0) throw new ArithmeticException("Modulus not positive: " + m); ... // Do the computation assert this.multiply(result).mod(m).equals(ONE) : this; return result; }
Иногда необходимо сохранить некоторые данные до выполнения вычисления, чтобы проверить постусловие. Можно сделать это с два assert
операторы и простой внутренний class, который сохраняет состояние одной или более переменных, таким образом, они могут быть проверены (или перепроверены) после вычисления. Например, предположите, что у Вас есть часть кода, который похож на это:
void foo(int[] array) { // Manipulate array ... // At this point, array will contain exactly the ints that it did // prior to manipulation, in the same order. }
Вот то, как Вы могли изменить вышеупомянутый метод, чтобы превратить текстовое утверждение постусловия в функциональный:
void foo(final int[] array) { // Inner class that saves state and performs final consistency check class DataCopy { private int[] arrayCopy; DataCopy() { arrayCopy = (int[]) array.clone(); } boolean isConsistent() { return Arrays.equals(array, arrayCopy); } } DataCopy copy = null; // Always succeeds; has side effect of saving a copy of array assert ((copy = new DataCopy()) != null); ... // Manipulate array // Ensure array has same ints in same order as before manipulation. assert copy.isConsistent(); }
Можно легко обобщить эту идиому, чтобы сохранить больше чем одно поле данных, и протестировать произвольно сложные утверждения относительно значений предварительного вычисления и поствычисления.
Вы могли бы испытать желание заменить первый оператор контроля (который выполняется исключительно для его побочного эффекта) следующим, более выразительным оператором:
copy = new DataCopy();
Не делайте эту замену. Оператор выше скопировал бы массив, утверждает ли, были включены, нарушая принцип, что у утверждений не должно быть никакой стоимости когда отключено.
Инвариант class является типом внутреннего инварианта, который применяется к каждому экземпляру class всегда, кроме тех случаев, когда экземпляр находится в переходе от одного непротиворечивого состояния до другого. Инвариант class может определить отношения среди многократных атрибутов, и должен быть истиной прежде и после того, как любой метод завершается. Например, предположите, что Вы реализуете структуру данных сбалансированного дерева некоторого вида. Инвариант class мог бы быть то, что дерево балансируется и должным образом упорядочивается.
Механизм утверждения не осуществляет определенного стиля для того, чтобы проверить инварианты. Иногда удобно, тем не менее, объединить выражения, которые проверяют необходимые ограничения в единственном внутреннем методе, который могут вызвать утверждения. Продолжая пример сбалансированного дерева, могло бы быть уместно реализовать закрытый метод, который проверял, что дерево было действительно сбалансировано согласно тому, чтобы диктовать структуры данных:
// Returns true if this tree is properly balanced private boolean balanced() { ... }
Поскольку этот метод проверяет ограничение, которое должно быть истиной прежде и после того, как любой метод завершается, каждый открытый метод и конструктор должны сразу содержать следующую строку до ее возврата:
assert balanced();
Является обычно ненужным поместить подобные проверки во главе каждого открытого метода, если структура данных не реализуется собственными методами. В этом случае возможно, что ошибка повреждения памяти могла повредить "собственную коллегу" структура данных промежуточный вызовы метода. Отказ утверждения во главе такого метода указал бы, что такое повреждение памяти произошло. Точно так же может быть желательно включать проверки инварианта class в глав методов в классах, состояние которых является поддающимся изменению другими классами. (Еще лучше, классы проекта так, чтобы их состояние не было непосредственно видимо к другим классам!)
Следующие разделы обсуждают темы, которые применяются только к ограниченным ресурсом устройствам и к системам, где утверждает, не должен быть отключен в поле. Если у Вас нет никакого интереса к этим темам, пропустите к следующему разделу, "Компилируя Файлы то Использование Утверждения".
Программисты, разрабатывающие приложения для ограниченных ресурсом устройств, могут хотеть разделить утверждения из файлов class полностью. В то время как это лишает возможности включать утверждениям в поле, оно также уменьшает размер файла class, возможно приводя к улучшенной производительности загрузки class. В отсутствие высококачественного JIT это могло привести к уменьшенному месту и улучшило производительность времени выполнения.
Средство утверждения не предлагает прямой поддержки разделения утверждений из файлов class. Оператор контроля может, однако, использоваться в соединении с идиомой "условной компиляции", описанной в Спецификации языка Java, позволяя компилятору устранить все трассировки их утверждает от файлов class, что это генерирует:
static final boolean asserts = ... ; // false to eliminate asserts if (asserts) assert <expr> ;
Программисты определенных критических систем могли бы хотеть гарантировать, что утверждения не отключаются в поле. Следующая статическая идиома инициализации препятствует тому, чтобы class был инициализирован, если его утверждения были отключены:
static { boolean assertsEnabled = false; assert assertsEnabled = true; // Intentional side effect!!! if (!assertsEnabled) throw new RuntimeException("Asserts must be enabled!!!"); }
Поместите этот статический инициализатор наверху своего class.
Для javac
компилятор, чтобы принять код, содержащий утверждения, следует использовать -source 1.4
параметр командной строки как в этом примере:
javac -source 1.4 MyClass.java
Этот флаг необходим, чтобы не вызвать исходные проблемы совместимости.
По умолчанию утверждения отключаются во времени выполнения. Два переключателя командной строки позволяют Вам выборочно включать или отключать утверждения.
Чтобы включить утверждениям при различных гранулярностях, используйте -enableassertions
, или -ea
, переключатель. Чтобы отключить утверждения при различных гранулярностях, используйте -disableassertions
, или -da
, переключатель. Вы определяете гранулярность с параметрами, что Вы обеспечиваете для переключателя:
...
...
Например, следующая команда выполняет программу, BatTutor
, с утверждениями, включенными в только пакете com.wombat.fruitbat
и его подпакеты:
java -ea:com.wombat.fruitbat... BatTutor
Если единственная командная строка содержит многократные экземпляры этих переключателей, они обрабатываются в порядке прежде, чем загрузить любые классы. Например, следующая команда работает BatTutor
программа с утверждениями, включенными в пакете com.wombat.fruitbat
но отключенный в class com.wombat.fruitbat.Brickbat
:
java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat BatTutor
Вышеупомянутые переключатели применяются ко всем загрузчикам class. С одним исключением они также применяются к системным классам (у которых нет явного загрузчика class). Исключение касается переключателей без параметров, которые (как обозначено выше) не применяются к системным классам. Это поведение облегчает включать, утверждает во всех классах за исключением системных классов, который является обычно требуемым.
Чтобы включить утверждениям во всех системных классах, используйте различный переключатель: -enablesystemassertions
, или -esa
. Точно так же, чтобы отключить утверждения в системных классах, использовать -disablesystemassertions
, или -dsa
.
Например, следующая команда работает BatTutor
программа с утверждениями, включенными в системных классах, так же как в com.wombat.fruitbat
пакет и его подпакеты:
java -esa -ea:com.wombat.fruitbat...
Состояние утверждения class (включил или отключил), устанавливается в то время, когда оно инициализируется, и не изменяется. Есть, однако, один угловой случай, который требует специальный режим. Это возможно, хотя обычно не требуемый, чтобы выполнить методы или конструкторов до инициализации. Это может произойти, когда иерархия class содержит зацикливание в своей статической инициализации.
Если оператор assert выполняется прежде, чем его class инициализируется, выполнение должно вести себя, как будто утверждения были включены в class. Эта тема обсуждается подробно в спецификации утверждений в Спецификации языка Java.
Добавление assert
ключевое слово к языку программирования Java не вызывает проблем с существующими ранее двоичными файлами (.class
файлы). Если Вы пытаетесь скомпилировать приложение, которое использует assert
как идентификатор, однако, Вы получите предупреждающее сообщение или сообщение об ошибке. Чтобы ослабить переход от мира где assert
юридический идентификатор к тому, где это не, компилятор поддерживает два режима работы в этом выпуске:
assert
как идентификатор, но предупреждения проблем. В этом режиме программам не разрешают использовать assert
оператор.assert
как идентификатор. В этом режиме программам разрешают использовать assert
оператор.Если Вы определенно не запрашиваете исходный режим 1.4 с -source 1.4
флаг, компилятор работает в исходном режиме 1.3. Если Вы забываете использовать этот флаг, программы, которые используют новое assert
оператор не будет компилировать. Наличие компилятора использует старую семантику в качестве своего поведения значения по умолчанию (то есть, позволяя assert
использоваться в качестве идентификатора), был сделан для максимальной исходной совместимости. Исходный режим 1.3, вероятно, будет постепенно сокращен в течение долгого времени.
Вот набор часто задаваемых вопросов относительно проекта средства утверждения.
AssertionError
КлассХотя оперативные реализации возможны, они по необходимости любой уродливы (требование if
оператор для каждого утверждения) или неэффективный (оценка условия, даже если утверждения отключаются). Далее, у каждой оперативной реализации есть свои собственные средства включения и отключения утверждений, который уменьшает утилиту этих реализаций, специально для отладки в поле. В результате этих недостатков утверждения никогда не становились частью культуры среди инженеров, использующих язык программирования Java. Добавление поддержки утверждения платформе получает хорошую возможность исправления этой ситуации.
Мы распознаем, что изменение языка является серьезным усилием, чтобы не быть предпринятым слегка. Подход библиотеки рассмотрели., однако, считали важным, что стоимость времени выполнения утверждений быть незначительным, если они отключаются. Чтобы достигнуть этого с библиотекой, программист вынуждается к твердому коду каждое утверждение как if
оператор. Много программистов не сделали бы этого. Или они опустили бы, если бы оператор и производительность пострадают, или они проигнорировали бы средство полностью. Отметьте также, что утверждения содержались в исходной спецификации Джеймса Гослинга для языка программирования Java. Утверждения были удалены из спецификации Дуба потому что ограничения времени, предотвращенные удовлетворительная разработка и реализация.
Мы рассмотрели предоставление такой услуги, но были неспособны убедить нас, что возможно привить это на язык программирования Java без массивных изменений к библиотекам платформы Java, и массивных несогласованностей между старыми и новыми библиотеками. Далее, мы не были убеждены, что такое средство сохранит простоту, которая является признаком языка программирования Java. В итоге мы пришли к выводу, что простое булево средство утверждения было довольно прямым решением и намного менее опасный. Это стоит отметить, что добавление булева средства утверждения на язык не устраняет добавлять законченное средство проекта согласно контракту в некоторое время в будущем.
Простое средство утверждения действительно включает ограниченной форме программирования стиля проекта согласно контракту. assert
оператор является подходящим для непубличного предварительного условия, постусловия и проверки инварианта class. Общедоступная проверка предварительного условия должна все еще быть выполнена проверками в методах, которые заканчиваются в частности задокументированные исключения, такой как IllegalArgumentException
и IllegalStateException
.
Обеспечение такой конструкции поощрило бы программистов помещать сложные встроенные утверждения, когда они лучше понижаются, чтобы разделить методы.
assert
как идентификатор?
Да, для исходных файлов. (Двоичные файлы для классов то использование assert
поскольку идентификатор будет продолжать хорошо работать.), Чтобы ослабить переход, мы реализовывали стратегию, посредством чего разработчики могут продолжать использовать assert
как идентификатор во время переходного периода.
Да. Файлы класса будут содержать звонки в новые методы ClassLoader И Class, такие как desiredAssertionStatus. Если файл class, содержащий звонки в эти методы, будет выполнен против более старого JRE (чей ClassLoader class не определяет методы), то программа перестанет работать во время выполнения, бросая NoSuchMethodError. Это обычно имеет место, что программы, используя новые средства не являются совместимыми с более старыми выпусками.
Нет никакого неопровержимого довода, чтобы ограничить тип этого выражения. Разрешение произвольных типов предоставляет удобство разработчикам, которые, например, хотят связать уникальный целочисленный код с каждым утверждением. Далее, это заставляет это выражение чувствовать себя подобно параметру System.out.println(...)
, который замечается как требуемый.
AssertionError
сгенерирован оператором контроля, в котором Expression2 отсутствует, почему не текст программы утверждаемого условия, используемого в качестве сообщения детали (например,"height < maxHeight
")?
В то время как выполнение так могло бы улучшить полноценность "из поля" утверждений в некоторых случаях, преимущество не выравнивает по ширине стоимость добавления всех тех строковых констант к .class
файлы и изображения времени выполнения.
AssertionError
предоставьте доступ к объекту, который генерировал его? Точно так же почему бы не передать произвольный объект от утверждения до AssertionError
конструктор вместо сообщения детали?
Доступ к этим объектам поощрил бы программистов пытаться восстановиться с отказов утверждения, который побеждает цель средства.
getFile
, getline
, getMethod
) на AssertionError
?
Эта услуга лучше всего предоставляется на Throwable
, таким образом, это может использоваться для всего throwables, не только ошибок утверждения. Мы улучшали Throwable
с getStackTrace
метод, чтобы обеспечить эту функциональность.
AssertionError
подкласс Error
вместо RuntimeException
?
Эта проблема была спорна. Экспертная группа обсудила это подробно, и пришла к выводу это Error
было более соответствующим, чтобы отговорить программистов пытаться восстановиться с отказов утверждения. Это является, вообще, трудным или невозможным локализовать источник отказа утверждения. Такой отказ указывает, что программа работает "за пределами известного пространства," и пытается продолжаться, выполнение, вероятно, будут вредны. Далее, соглашение диктует, что методы определяют большинство исключений на этапе выполнения, которые они могут бросить (с @throws
комментарии документа). Имеет небольшой смысл включать в спецификацию метода обстоятельства, при которых это может генерировать отказ утверждения. Такая информация может быть расценена как деталь реализации, которая может измениться от реализации до реализации и выпуска к выпуску.
Это - твердое требование что это быть возможным включить утверждениям в поле для улучшенного удобства обслуживания. Было бы возможно также разрешить разработчикам устранять утверждения из объектных файлов во время компиляции. Утверждения могут содержать побочные эффекты, хотя они не должны, и такой флаг мог поэтому изменить поведение программы существенными способами. Это просматривается как хорошая вещь, что есть только одна семантика, связанная с каждой допустимой программой Java. Кроме того, мы хотим поощрить пользователей уезжать, утверждает в объектных файлах, таким образом, им можно включить в поле. Наконец, спецификация требует, чтобы утверждения вели себя, как будто включенный, когда class работает прежде, чем это будет инициализировано. Было бы невозможно предложить им семантику, если бы утверждения были разделены от файла class. Отметьте, однако, что стандартная "идиома условной компиляции", описанная в Спецификации языка Java, может использоваться, чтобы достигнуть этого эффекта для разработчиков, которые действительно хотят это.
Иерархическое управление полезно, поскольку программисты действительно используют иерархии пакета, чтобы организовать их код. Например, древовидная пакетом семантика позволяют утверждениям быть включенными или отключенными во всем Swing когда-то.
setClassAssertionStatus
возвратите a boolean
вместо того, чтобы выдать исключение, если это вызывается, когда очень поздно установить состояние утверждения (то есть, если именованный class был уже инициализирован)?
Никакое действие (кроме, возможно, предупреждающего сообщения) не является необходимым или требуемым, если очень поздно установить состояние утверждения. Исключение кажется незаконно тяжелым.
setDefaultAssertionStatus
и setAssertionStatus
?
Ясность в именовании метода для большей пользы. Перегрузка имеет тенденцию вызывать беспорядок.
Это не является четким, что было бы любое использование для получающегося метода. Метод не разрабатывается для использования прикладного программиста, и это кажется нецелесообразным, чтобы сделать это медленнее и более сложным чем необходимый.
RuntimePermission
препятствовать тому, чтобы апплеты позволили/отключили утверждениям?
В то время как у апплетов нет никакой причины вызвать любой из ClassLoader
методы для того, чтобы изменить состояние утверждения, позволяя им сделать так кажутся безопасными. В худшем случае апплет может смонтировать слабую атаку "отказ в обслуживании", включая утверждениям в классах, которые должны все же быть инициализированы. Кроме того апплеты могут только влиять на утверждать состояние классов, которые должны быть загружены загрузчиками class, к которым могут получить доступ апплеты. Там уже существует a RuntimePermission
препятствовать тому, чтобы недоверяемый код получил доступ к загрузчикам class (getClassLoader
).
Такая конструкция поощрила бы людей встраивать сложный код утверждения, который мы просматриваем как плохую вещь. Далее, это прямо, чтобы запросить утверждать состояние на текущем API, если Вы чувствуете, что Вы должны:
boolean assertsEnabled = false; assert assertsEnabled = true; // Intentional side-effect!!! // Now assertsEnabled is set to the correct value
Немного программистов знают о факте, что конструкторы class и методы могут работать до его инициализации. Когда это происходит, довольно вероятно, что инварианты class еще не были установлены, который может вызвать серьезные и тонкие ошибки. Любое утверждение, которое выполняется в этом состоянии, вероятно, перестанет работать, предупреждая программиста к проблеме. Таким образом для программиста обычно полезно выполнить все утверждения, с которыми встречаются в то время как в этом состоянии.