Because assertions may be disabled, programs must not assume that the expressions contained in assertions will be evaluated. Thus, these boolean expressions should generally be free of side effects: evaluating such a boolean expression should not affect any state that is visible after the evaluation is complete. It is not illegal for a boolean expression contained in an assertion to have a side effect, but it is generally inappropriate, as it could cause program behavior to vary depending on whether assertions were enabled or disabled.
Along similar lines, assertions should not be used for argument-checking in public methods. Argument-checking is typically part of the contract of a method, and this contract must be upheld whether assertions are enabled or disabled. Another problem with using assertions for argument checking is that erroneous arguments should result in an appropriate runtime exception (such as IllegalArgumentException, IndexOutOfBoundsException or NullPointerException). An assertion failure will not throw an appropriate exception. Again, it is not illegal to use assertions for argument checking on public methods, but it is generally inappropriate.
All section number references to The Java Language Specification (JLS) contained in this document refer to the second edition.
StatementWithoutTrailingSubstatement: <All current possibilities, as per JLS, Section 14.5> AssertStatement AssertStatement: assert Expression1 ; assert Expression1 : Expression2 ;In both forms of the assert statement, Expression1 must have type boolean or a compile-time error results. In the second form, Expression2 must have a value or a compile-time error results. In other words, Expression2 must not be void. (A void expression is a method invocation that invokes a method that is declared void (JLS 15.1).)
If assertions are disabled in a class, an assert statement contained in that class does nothing. In particular, its "arguments" ( Expression1 and, if it is present, Expression2) are not evaluated. Execution of an assert statement that is contained in a class in which assertions are disabled always completes normally.
If assertions are enabled in a class, an assert statement contained in that class is executed by first evaluating Expression1. If evaluation of Expression1 completes abruptly for some reason, the assert statement completes abruptly for the same reason. Otherwise, execution continues by making a choice based on the value of Expression1:
public class Foo {
public static void main(String args[]) {
Baz.testAsserts(); // Will execute after Baz is initialized.
}
}
class Bar {
static {
Baz.testAsserts(); // Will execute before Baz is initialized!
}
}
class Baz extends Bar {
static void testAsserts(){
boolean enabled = false;
assert enabled = true;
System.out.println("Asserts " + (enabled ? "enabled" : "disabled"));
}
}
Invoking Baz.testAsserts() causes Baz to get initialized.
Before this can happen, Bar must get initialized. Bar's
static initializer again invokes Baz.testAsserts(). Because initialization
of Baz is already in progress by the current thread, the second
invocation executes immediately, though Baz is not initialized
(JLS 12.4.2).
If an assert statement executes before its class is initialized, as in the above example, the execution must behave as if assertions were enabled in the class. In other words, if the program above is executed without enabling assertions, it must print:
Asserts enabled Asserts disabled
Reachability: An assert statement can complete normally iff it is reachable.
/**
* Sets the default assertion status for this class loader. This setting
* determines whether classes loaded by this class loader and initialized
* in the future will have assertions enabled or disabled by default.
* This setting may be overridden on a per-package or per-class basis by
* invoking {@link #setPackageAssertionStatus(String,boolean)} or {@link
* #setClassAssertionStatus(String,boolean)}.
*
* @param enabled true if classes loaded by this class loader
* will henceforth have assertions enabled by default,
* false if they will have assertions disabled by default.
*/
public void setDefaultAssertionStatus(boolean enabled);
If, at the time that a class is initialized, its class loader has been
given specific instructions regarding the assertion status of the class's
package name or its class name (via either of the two new methods in ClassLoader
described below), those instructions take precedence over the class loader's
default assertion status. Otherwise, the class's assertions are enabled
or disabled as specified by its class loader's default assertion status.
The following method allows the invoker to set a per-package default assertion status. Note that a per-package default actually applies to a package and any "subpackages."
/**
* Sets the package default assertion status for the named
* package. The package default assertion status determines the
* assertion status for classes initialized in the future that belong
* to the named package or any of its "subpackages."
*
* A subpackage of a package named p is any package whose name
* begins with "p." . For example, javax.swing.text is
* a subpackage of javax.swing, and both java.util
* and java.lang.reflect are subpackages of java.
*
* In the event that multiple package defaults apply to a given
* class, the package default pertaining to the most specific package
* takes precedence over the others. For example, if
* java.lang and java.lang.reflect both have
* package defaults associated with them, the latter package
* default applies to classes in java.lang.reflect.
*
* Package defaults take precedence over the class loader's default
* assertion status, and may be overridden on a per-class basis by
* invoking {@link #setClassAssertionStatus(String,boolean)}.
*
* @param packageName the name of the package whose package default
* assertion status is to be set. A null value
* indicates the unnamed package that is "current"
* (JLS 7.4.2).
* @param enabled true if classes loaded by this classloader
* and belonging to the named package or any of its subpackages
* will have assertions enabled by default, false if they
* will have assertions disabled by default.
*/
public synchronized void setPackageAssertionStatus(String packageName,
boolean enabled);
The following method is used to set assertion status on a per-class basis:
/** * Sets the desired assertion status for the named top-level class in * this class loader and any nested classes contained therein. * This setting takes precedence over the class loader's default * assertion status, and over any applicable per-package default. * This method has no effect if the named class has already been * initialized. (Once a class is initialized, its assertion status cannot * change.) * * If the named class is not a top-level class, this call will have no * effect on the actual assertion status of any class, and its return * value is undefined. * * @param className the fully qualified class name of the top-level class * whose assertion status is to be set. * @param enabled true if the named class is to have assertions * enabled when (and if) it is initialized, false if the * class is to have assertions disabled. */ public void setClassAssertionStatus(String className, boolean enabled);The following method clears any assertion status settings associated with a class loader:
/** * Sets the default assertion status for this class loader to * false and discards any package defaults or class assertion * status settings associated with the class loader. This call is * provided so that class loaders can be made to ignore any command line * assertion status directives and "start with a clean slate." */ public void clearAssertionStatus();Finally, a method is added to Class to allow the desired assertion status for a specified class to be queried. Few programmers will have any need for this method; it is provided for the benefit of the JRE itself. (It allows a class to determine at the time that it is initialized whether assertions should be enabled.)
/** * Returns the assertion status that would be assigned to this * class if it were to be initialized at the time this method is invoked. * If this class has had its assertion status set, the most recent * setting will be returned; otherwise, if any package default assertion * status pertains to this class, the most recent setting for the most * specific pertinent package default assertion status is returned; * otherwise, if this class is not a system class (i.e., it has a * class loader) its class loader's default assertion status is returned; * otherwise, the system class default assertion status is returned. * * Few programmers will have any need for this method; it is provided * for the benefit of the JRE itself. (It allows a class to determine at * the time that it is initialized whether assertions should be enabled.) * Note that this method is not guaranteed to return the actual * assertion status that was (or will be) associated with this class when * it was (or will be) initialized. * * @return the desired assertion status of the specified class. * @see setClassAssertionStatus * @see setPackageAssertionStatus * @see setDefaultAssertionStatus */ public boolean desiredAssertionStatus();The new ClassLoader instance methods for setting desired assertion status will generally not be used by normal programs, but by interpreters, such as java, and by other execution environments. Interpreters should provide some interpreter-specific facility for users to enable and disable asserts. One possible approach is described in Appendix II.
The new ClassLoader instance methods for setting desired assertion status cannot be used on system classes, which do not have a class loader. No public APIs are provided to enable or disable asserts on system classes, but JRE implementors are strongly encouraged to implement a non-public mechanism whereby their interpreters can set the desired assertion status for system classes. (Such a mechanism is briefly described in Appendix IV.)
/**
* Thrown to indicate that an assertion has failed.
*
* The seven one-argument public constructors provided by this
* class ensure that the assertion error returned by the invocation:
*
* new AssertionError(expression)
*
* has as its detail message the string conversion of expression
* (as defined in The Java Language Specification, Section 15.18.1.1)
* regardless of the type of expression.
*/
public class AssertionError extends Error {
/**
* Constructs an AssertionError with no detail message.
*/
public AssertionError();
/**
* Constructs an AssertionError with its detail message derived from
* the specified object reference, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*
* If the specified object is an instance of Throwable, it
* becomes the cause of the newly constructed assertion error.
*/
public AssertionError(Object detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified boolean, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(boolean detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified char, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(char detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified int, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(int detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified long, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(long detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified float, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(float detailMessage);
/**
* Constructs an AssertionError with its detail message derived from
* the specified double, which is converted to a string as
* defined in The Java Language Specification, Section 15.18.1.1.
*/
public AssertionError(double detailMessage);
}
if (i%3 == 0) {
...
} else if (i%3 == 1) {
...
} else { // (i%3 == 2)
...
}
Whenever you come across a comment that asserts an invariant, you should
change it to an assert:
if (i % 3 == 0) {
...
} else if (i%3 == 1) {
...
} else {
assert i%3 == 2;
...
}
The above example, where an assert protects the else-clause in a multiway
if-statement is quite common. Note, incidentally, that the assertion in
the above example may fail if i is negative, as the %
operator is not a true mod operator, but computes the remainder,
which may be negative.
switch(suit) {
case Suit.CLUBS:
...
break;
case Suit.DIAMONDS:
...
break;
case Suit.HEARTS:
...
break;
case Suit.SPADES:
...
}
It is probably the case that the programmer believes that one of the four
cases in the above switch statement will always be executed. This assumption
may be tested by adding the following default case:
default: assert false;More generally, the statement
assert false;should be placed at locations the programmer believes to be "unreached" For example, suppose you have a method that looks like this:
void foo() {
for (...) {
if (...)
return;
}
// Execution should never reach this point!!!
}
The final comment should be replaced by
assert false;This technique must be used with some discretion; if a statement is unreachable (JLS 14.20), you'll get a compile time error if you try to assert that it is unreached.
/**
* 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);
}
This convention is unaffected by the addition of the assert construct.
This construct is inappropriate for such preconditions, as the enclosing
method guarantees that it will enforce the argument checks whether or not
assertions are enabled. Further, the assert construct does not
throw an exception of the specified type.
If, however, there is a precondition on a nonpublic method and the author of a class believes the precondition to hold no matter what a client does with the class, then an assertion is appropriate:
/**
* Sets the refresh interval (which must correspond to a legal frame rate).
*
* @param interval refresh interval in milliseconds.
*/
private void setRefreshInterval(int interval) {
// Validate adherence to precondition in nonpublic method
assert interval > 0 && interval <= 1000/MAX_REFRESH_RATE;
... // Set the refresh interval
}
Note, by the way, that the above assertion will fail if MAX_REFRESH_RATE
is greater than 1000 and the user selects a refresh rate greater
than 1000; this would, in fact, indicate a bug in the library!
/**
* 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);
if (!this.gcd(m).equals(ONE))
throw new ArithmeticException(this + " not invertible mod " + m);
... // Do the computation
assert this.multiply(result).mod(m).equals(ONE);
return result;
}
In practice, one would not check the second precondition, (this.gcd(m).equals(ONE))
prior to performing the computation, because it is wasteful; this precondition
is checked as a side effect of performing the modular multiplicative inverse
computation by standard algorithms.
Occasionally, it is necessary to save some data prior to performing a computation in order to check a postcondition after it is complete. This can be done with two assert statements and the help of a simple inner class designed to save 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:
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.
}
Here is how you could modify the above method to turn the textual assertion
into a functional one:
import java.util.Arrays;
void foo(final int[] array) {
class DataCopy {
private int[] arrayCopy;
DataCopy() { arrayCopy = (int[]) array.clone(); }
boolean isConsistent() { return Arrays.equals(array, arrayCopy); }
}
DataCopy copy = null;
// Never fails. If asserts enabled, saves array copy as side effect.
assert (copy = new DataCopy()) != null;
... // Manipulate array
assert copy.isConsistent();
}
Note that this idiom easily generalizes to save more than one data field,
and to test arbitrarily complex assertions concerning pre-computation and
post-computation values. This idiom is less than pretty, but it is expedient.
The first assert statement (which is executed solely for its side
effect) could be replaced by the more expressive:
copy = new DataCopy();but this would copy the array whether or not asserts were enabled, violating the dictum that asserts should have no cost when disabled.
// Returns true if this tree is properly balanced
private boolean balanced() {
...
}
This method is a class invariant. It should be always be true before
and after any method completes. To check that this is indeed the case,
each public method and constructor should contain the line:
assert balanced();immediately prior to each return. It is generally overkill 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 "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 head 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!)
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) {
...
}
A static method called holdsLock has been added to Thread
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 with an assertion
validating the precondition:
// 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
}
Note that it is also possible to write a lock-status assertion asserting
that a given lock isn't held.
The assertion facility offers no direct support for stripping assertions out of class files. However, the assert statement may be used in conjunction with the "conditional compilation" idiom described in JLS 14.20:
static final boolean asserts = ... ; // false to eliminate asserts if (asserts) assert <expr> ;If asserts are used in this fashion, the compiler is free to eliminate all traces of these asserts from the class files that it generates. It is recommended that this be done where appropriate to support generation of code for resource-constrained devices.
static {
boolean assertsEnabled = false;
assert assertsEnabled = true; // Intentional side effect
if (!assertsEnabled)
throw new RuntimeException("Asserts must be enabled!");
}
The following switch enables assertions at various granularities:
java [ -enableassertions | -ea ] [:<package name>"..." | :<class name> ]With no arguments, the switch enables assertions by default. With one argument ending in "...", the switch enables assertions in the specified package and any subpackages by default. If the argument is simply "...", the switch enables assertions in the unnamed package in the current working directory. With one argument not ending in "...", the switch enables assertions in the specified class.
The following switch disables assertions in similar fashion:
java [ -disableassertions | -da ] [:<package name>"..." | :<class name> ]If a single command line contains multiple instances of these switches, they are processed in order before loading any classes. So, for example, to run a program with assertions enabled only in package com.wombat.fruitbat (and any subpackages), the following command could be used:
java -ea:com.wombat.fruitbat... <Main Class>To run a program with assertions enabled in package com.wombat.fruitbat but disabled in class com.wombat.fruitbat.Brickbat, the following command could be used:
java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat <Main Class>The above switches apply to all class loaders, and to system classes (which do not have a class loader). There is one exception to this rule: in their no-argument form, the switches do not apply to system classes. This makes it easy to turn on asserts in all classes except for system classes. A separate switch is provided to enable asserts in all system classes (that is, to set the default assertion status for system classes to true).
java [ -enablesystemassertions | -esa ]For symmetry, a corresponding switch is provided to disable asserts in all system classes, though it is not clear that there exists a use for this switch:
java [ -disablesystemassertions | -dsa ]
-source <release>where <release> can be "1.3" or "1.4". In the absence of this flag, the behavior will default to "1.3" for maximal source compatibility. Support for 1.3 source compatibility will likely be phased out over time.
Class ClassLoader gets three new private fields, which it uses to keep track of desired assertion status directives:
private boolean defaultAssertionStatus = false; // Maps String packageName to Boolean package default assertion status private Map packageAssertionStatus = new HashMap(); // Maps String fullyQualifiedClassName to Boolean assertionStatus private Map classAssertionStatus = new HashMap();These fields are maintained by the four new public ClassLoader methods in the obvious fashion. In fact, the only thing that these methods do is to modify these fields (or the maps they reference).
The compiler adds a synthetic field to every class that contains one or more assert statements. The synthetic field contains the complement of the actual assertion status of the class:
static final boolean $assertionsDisabled = !<EnclosingTopLevelClassName>.class.desiredAssertionStatus();This declaration must be placed before all other static variable declarations and static initializers in the class. The name of the field is not part of the specification: it is local to the class and can vary from implementation to implementation and class to class. This field may occur in contexts where static fields are not permitted by the Java programming language, such as inner classes; because it is a synthetic field, this does not present a problem. While the presence of such a field violates the JLS, it does not violate the JVMS.
The assert statement, then, is merely syntactic sugar for this:
do {
if (!($assertionsDisabled || (Expression1)))
throw new java.lang.AssertionError(Expression2);
} while(false);
If Expression2 is not present in the assert
statement, it is omitted from the above expansion.
The surrounding do-while loop is merely an artifice to transform the if statement to the correct syntactic category (StatementWithoutTrailingSubstatement), and has no semantics associated with it. Note that this implementation works equally well in static methods, instance methods, constructors, static initializers, and instance initializers.
The runtime does not need to treat this code specially in order to "strip out" assertions from classes when they're disabled! Because $assertionsDisabled is final, the JIT can easily determine that the entire do statement has no effect, and eliminate it in the compiled code that it generates. Present day JITs (including the Java HotSpot™ performance engine) do this optimization.
Note also that $assertionsDisabled resolves to the so-named field in the "declaring class" for the containing method. The resulting behavior is clearly desirable, though it may be somewhat surprising. If one class extends another, and assertions are enabled only in the subclass, assertions contained in (any) inherited superclass methods will not be executed.
Note that this implementation does not support control over assertions in system classes, but it can easily be extended to do so as follows. The interpreter makes the command line flags indicating desired assertion status available, via an undocumented JVM entry point. The Class.desiredAssertionStatus method is modified to delegate to this entry point for system classes (which have no class loader). As an optimization, this method can delegate to the JVM for all classes whose class loader has not yet had any of the new ClassLoader methods invoked. Thus, the ClassLoader needn't initialize its packageAssertionStatus and classAssertionStatus fields unless one of the four "desired assertion status directives" is invoked on it. Once this happens, the ClassLoader creates the maps and dumps into them all of the directives described by command line flags. (This requires a second undocumented JVM entry point to obtain the command-line directives.)
Note that this technique has the added advantage of allowing the assert statement to be used in "low-level" system classes. Little java code must be executed in order to determine the desired assertion status of a system class, so it can be done early in the JVM bootstrap sequence. We anticipate that this technique will allow asserts in all system classes except perhaps Object.
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. Adding assertion support to the
platform stands a good chance of rectifying this situation over time.
We recognize that a language change is a serious effort, not to
be undertaken lightly. The library approach was considered seriously. 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'd omit the if statement and
performance would suffer, or they'd ignore the facility entirely. Note
also that assertions were contained in James Gosling's original specification
for the Java programming language, nee Oak. Assertions were removed from
the Oak specification because time constraints prevented a satisfactory
design and implementation.
We seriously 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 clear knee-in-the-curve,
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.
The simple assertion facility does enable a limited form of design-by-contract style programming. The assert statement is appropriate for postcondition and class invariant checking, and precondition checking in non-public methods. Precondition checking in public methods should still be performed by checks inside methods that result in particular, documented exceptions, such as IllegalArgumentException and IllegalStateException.
Providing such a construct would encourage programmers to put complex
assertions inline, when they are better relegated to separate methods.
Yes, for source files. (Binaries for classes that use assert
as an identifier will continue to work fine.) To ease the transition, we
describe a strategy whereby developers can continue
to use 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. While
it would be possible to circumvent this problem by catching the NoSuchMethodError,
Java platform implementors are under no obligation to do this.
There is no compelling reason to restrict the type of this expression.
Allowing arbitrary types provides convenience, for example, allowing developers
to easily associate a unique integer code with each assertion. Further,
it makes this expression feel like the argument to System.err.println(...),
which is desirable.
While doing so might improve out-of-the-box usefulness of assertions
in some cases, the benefit doesn't justify the cost of adding all these
string constants to .class files and runtime images.
Access to these objects would encourage programmers to attempt to
recover from assertion failures, which defeats the purpose of the facility.
This facility is best provided on Throwable, so it may
be used for all throwables, not just assertion errors. We enhanced Throwable
with the getStackTrace method, providing programmatic access to
this information for every stack frame.
This issue was controversial. The expert group discussed it at 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 (via "@throws" tags). It makes little
sense to include in a method's specification the circumstances under which
it may generate an assertion failure. This information may be regarded
as an implementation detail, which can change from implementation to implementation
and release to release.
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. However, since assertions can contain side effects (though they generally
should not), such a flag could 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 program. Also, we want to encourage users to leave asserts
in object files so they can be enabled in the field. Finally, the standard
"conditional compilation" idiom described in JLS 14.20 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 in one fell
swoop.
No action (other than perhaps a warning message) is necessary or
desirable if it's too late to set the assertion status. Furthermore, it
is, in general, difficult for the programmer to predict whether a given
class has been initialized.
Clarity in method naming is for the greater good.
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 desired assertion status, allowing them to do so
seems harmless. At worst, an applet can mount a weak denial-of-service
attack by turning on asserts in classes that have yet to be initialized.
Moreover, applets can only affect the assertion status of classes that
are to be initialized by class loaders that the applets can get their hands
on. 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:
if (assertsEnabled()) {
...
}
Further, it is straightforward to query the assertion status atop the current
API, if you feel you must:
boolean assertsEnabled = false; assert assertsEnabled = true; // Intentional side effect!!! // Now assertsEnabled is set to the correct value
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.