Java 2 SDK for Solaris Developer's Guide

Assertion Facility

An assertion is understood to be a statement containing a boolean expression that the programmer believes to be true at the time the statement is executed. For example, after unmarshalling all of the arguments from a data buffer, a programmer might assert that the number of bytes of data remaining in the buffer is zero. The system executes the assertion by evaluating the boolean expression and reporting an error if the expression evaluates to false. By verifying that the boolean expression is indeed true, the system corroborates the programmer's knowledge of the program thus increasing the possibility that the program is free of errors.

Assertion checking may be disabled for increased performance. Typically, assertion checking is enabled during program development and testing and disabled for deployment.

Because assertions may be disabled, programs must not assume that the boolean expressions contained in assertions will be evaluated. Thus these expressions should be free of side effects. That is, evaluating such an expression should not affect any state that is visible after the evaluation is complete. Although it is not illegal for a boolean expression contained in an assertion to have a side effect, it is generally inappropriate, as it could cause program behavior to vary depending on whether assertions are enabled or disabled.

Similarly, 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.

For more details, choose from the following links:

Compiling

In order for the javac bytecode compiler to accept code containing assertions, you must use the -source 1.4 command-line option as in this example:


javac -source 1.4 MyClass.java

Syntax

A new keyword is added to the language. Use of the assert keyword is governed by one modified production and one new production in the grammar:


StatementWithoutTrailingSubstatement:
           <All current possibilities, as per JLS,
              Section 14.4> AssertStatement          
AssertStatement:
   assert Expression1;
   assert Expression1 : Expression2; 

In both forms of the assert statement, Expression1 must be of type boolean or a compile-time error occurs.

Semantics

If assertions are disabled in a class, the assert statements contained in that class have no effect. If assertions are enabled, the first expression is evaluated. If it evaluates to false, an AssertionError is thrown. If the assertion contains a second expression (preceded by a colon), this expression is evaluated and passed to the constructor of the AssertionError; otherwise the parameterless constructor is used. (If the first expression evaluates to true, the second expression is not evaluated.)

If an exception is thrown while either expression is being evaluated, the assert statement completes abruptly, throwing this exception.

Enabling and Disabling Assertions

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

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 "...", assertions are enabled in the specified package and any subpackages by default. If the argument is simply "...", assertions are enabled in the unnamed package in the current working directory. With one argument not ending in "...", assertions are enabled 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. 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... 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 <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 (i.e., to set the default assertion status for system classes to true).


 java [ -enablesystemassertions | -esa ]

For symmetry, a corresponding switch is provided to enable asserts in all system classes.


java [ -disablesystemassertions | -dsa ]

Enabling and Disabling Assertions Programmatically

Most programmers will not need to use the following methods. They are provided for those writing interpreters or other execution environments.

Setting the Default Assertion Status for a Class Loader

Each class loader maintains a default assertion status, a boolean value that determines whether assertions are, by default, enabled or disabled in new classes that are subsequently initialized by the class loader. A newly created class loader's default assertion status is false (disabled). It can be changed at any time by invoking a new method in class ClassLoader:

public void setDefaultAssertionStatus(boolean enabled)

If, at the time that a class is loaded, 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.

Setting the Assertion Status for a Package and its Subpackages

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.

public void setPackageAssertionStatus(String packageName, boolean enabled);

Setting the Assertion Status for a Class and its Nested Classes

The following method is used to set assertion status on a per-class basis:

public void setClassAssertionStatus(string className, boolean enabled);

Resetting to the Class Loader Default Assertion Status

The following method clears any assertion status settings associated with a class loader:

public void clearAssertStatus();

Usage Notes

The material contained in this section is not part of the assert specification, instead it is intended to provide information about the use of the facility. In the parlance of the standards community, the information in this section is non-normative.

You will find examples of appropriate and inappropriate use of the assert construct. The examples are not exhaustive and are meant to convey the intended usage of the construct.

Internal Invariants

In general, it is appropriate to frequently use short assertions indicating important assumptions concerning a program's behavior.

In the absence of an assertion facility, many programmers use comments in the following way:


 if (i%3 == 0) {
        ...
    } else if (i%3 == 1) {
        ...
    } else { // (i%3 == 2)
        ...
    }

When your code contains a construct that asserts an invariant, you should change it to an assert. To change the above example (where an assert protects the else clause in a multiway if-statement), you might do the following:


if (i % 3 == 0) {
        ...
    } else if (i%3 == 1) {
        ...
    } else {
        assert i%3 == 2;
        ...
    }

Note, 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.

Control-Flow Invariants

Another good candidate for an assertion is a switch statement with no default case.

For example:


 switch(suit) {
      case Suit.CLUBS:
        ...
        break;

      case Suit.DIAMONDS:
        ...
        break;

      case Suit.HEARTS:
        ...
        break;

      case Suit.SPADES:
        ...
    }

The programmer probably assumes that one of the four cases in the above switch statement will always be executed. To test this assumption, add the following default case:


default:
        assert false;

More generally, the following statement should be placed at any location the programmer assumes will not be reached.


 assert false;

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


 void foo() {
        for (...) {
            if (...)
                return;
         }
         // Execution should never reach this point!!!
    }

Replace the final comment with:


assert false;

Note, use this technique with discretion. If a statement is unreachable as defined in (JLS 14.19), you will see a compile time error if you try to assert that it is unreached.

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.

Preconditions

By convention, preconditions on public methods are enforced by explicit checks inside methods resulting in particular, specified exceptions. For example:


 /**
     * 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. An assert 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 entirely appropriate. For example:


  /**
    * Sets the refresh interval (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;

        ... // Set the refresh interval
    }

Note, 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!

Postconditions

Postcondition checks are best implemented via assertions, whether or not they are specified in public methods. For example:


 /**
     * 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:


 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;

        // Always succeeds; has side effect of saving a copy of array
        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.

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.

Class Invariants

As noted above, assertions are appropriate for checking internal invariants. The assertion mechanism itself does not enforce any particular style for doing so. It is sometimes convenient to combine many expressions that check required constraints into a single internal method that can then be invoked by assertions. For example, suppose one were to implement a balanced tree data structure of some sort. 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:


 // Returns true if this tree is properly balanced
    private boolean balanced() {
        ...
    }

This method is a class invariant. It should 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 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 head of methods in classes whose state is modifiable by other classes. (Better yet, design classes so that their state is not directly visible by other classes!)

Removing all Trace of Assertions from Class Files

Programmers developing 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. However, the assert statement may be used in conjunction with the "conditional compilation" idiom described in JLS 14.19:


 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.

Requiring that Assertions are Enabled

Programmers of certain critical systems might wish to ensure that assertions are not disabled in the field. Here is an idiom that prevents a class from being loaded if assertions have been disabled for that class:


  static {
        boolean assertsEnabled = false;
        assert assertsEnabled = true; // Intentional side effect!!!
        if (!assertsEnabled)
            throw new RuntimeException("Asserts must be enabled!!!");
    }

Source Compatibility

The addition of the assert keyword to the Java Programming Language causes existing programs that use assert as an identifier to become invalid. The addition of this keyword does not, however, cause any problems with the use of preexisting binaries (.class files). In order to ease the transition from a world where assert is a legal identifier to one where it isn't, the compiler supports two modes of operation in this release.

To enable assertions, use the following command line switch.


 -source 1.4

In the absence of this flag, the behavior defaults to "1.3" for maximal source compatibility. Support for 1.3 source compatibility is likely to be phased out over time.

Design FAQ

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

Design FAQ - General Questions

  1. Why provide an assertion facility at all, given that one can program assertions atop the Java programming language with no special support?

    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 Java culture. Adding assertion support to the platform stands a good chance of rectifying this situation.

  2. Why does this facility justify a language change, as opposed to a library solution?

    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 Java. Assertions were removed from the Oak specification because time constraints prevented a satisfactory design and implementation.

  3. Why not provide a full-fledged design-by-contract facility with preconditions, postconditions and class invariants, like the one in the Eiffel programming language?

    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 Java's hallmark. 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.

    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. Precondition checking should still be performed by checks inside methods that result in particular, documented exceptions, such as IllegalArgumentException and IllegalStateException.

  4. In addition to boolean assertions, why not provide an assert-like construct to suppress the execution of an entire block of code if assertions are disabled?

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

Design FAQ - Compatibility

  1. Won't the new keyword cause compatibility problems with existing programs that use assert as an identifier?

    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 using assert as an identifier during a transitional period. See Source Compatibility.

Design FAQ - Syntax and Semantics

  1. Why allow primitive types in Expression2?

    There is no compelling reason to restrict the type of this expression. Allowing arbitrary types provides convenience for developers who for example want to associate a unique integer code with each assertion. Further, it makes this expression seem like System.out.print(...), which is desirable.

Design FAQ - The AssertionError Class

  1. When an AssertionError is generated by an assert statement in which Expression2 is absent, why isn't the program text of the asserted condition used as the detail message (e.g., "height < maxHeight")?

    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 those string constants to .class files and runtime images.

  2. Why doesn't an AssertionError allow access to the object that generated it? Similarly, why not pass an arbitrary object from the assertion to the AssertionError in place of a detail message?

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

  3. Why not provide context accessors (like getFile, getLine, getMethod) on AssertionError?

    This facility is best provided on Throwable, so it may be used for all throwables, and not just assertion errors. We intend to enhance Throwable to provide this functionality in the same release in which the assertion facility first appears.

  4. Why is AssertionError a subclass of Error rather than RuntimeException?

    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 (via "@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.

Design FAQ - Enabling and Disabling Assertions

  1. Why not provide a compiler flag to completely eliminate assertions from object files?

    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 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 Java program. Also, we want to encourage users to leave asserts in object files so they can be enabled in the field. Finally, the standard Java "conditional compilation idiom" described in JLS 14.19 can be used to achieve this effect for developers who really want it.

  2. Why does setPackageAssertionStatus have package-tree semantics instead of the more obvious package semantics?

    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.

  3. Why does setClassAssertionStatus return a boolean instead of throwing an exception if it is invoked when it's too late to set the assertion status (i.e., the named class has already been loaded)?

    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.

  4. Why not overload a single method to take the place of setDefaultAssertionStatus and setAssertionStatus?

    Clarity in method naming is for the greater good.

  5. Why is there no RuntimePermission to prevent applets from enabling/disabling assertions?

    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 turning on asserts in classes that have yet to be loaded. 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).

  6. Why not provide a construct to query the assert status of the containing class?

    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 assert 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