Assertions


Overview

An assertion is a statement that tests an assumption.

assert boolean [ : expression ] ;

For example:

assert i % 3 == 2 : i;

The value of expression is passed to the appropriate AssertionError constructor. Assertion failures are generally labeled in the stack trace with the file and line number from which they were thrown.

Assertions are cpu intensive, and for this reason are disabled by default when a program is started. Because assertions may be disabled, programs must not assume assertions will be evaluated.

Do not use assertions for public method argument checking, as an assertion failure will not throw an appropriate exception.

Usage

Use assert statements in switch statements with no default case:

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

      case Suit.DIAMONDS:
        ...
        break;

      case Suit.HEARTS:
        ...
        break;

      case Suit.SPADES:
        ...
    
      default:
        assert false : suit; 
    } 

Place assertions at locations that should not be reached:

    
    void foo() 
    {
        for (...) 
        {
            if (...)
                return;
        }

        // Execution should never reach this point!
        assert false; 
    } 

Use assert to verify the lock status of an object:

    
    // Recursive helper method 

    private int find(Object key, Object[] arr, int start, int len) 
    {
        // lock-status assertion 
        assert Thread.holdsLock(this); 
        ...
    } 

The following public method uses an assert statement to check a post condition:

    
    /**
     * Return 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;
    }

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

    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 of a postcondition into a functional one:

    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();
     } 

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

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

    
    copy = new DataCopy(); 

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

Remove assertions from class files Files

The assert statement can be used in conjunction with conditional compilation, to eliminate all traces of asserts from class files.

    
    static final boolean asserts = false; 

    if (asserts)
        assert expr ; 

Require an assertion

The following static prevents a class from being initialized if its assertions have been disabled:

    
    static 
    {
        boolean assertsEnabled = false;

        // Intentional side effect!!!
        assert assertsEnabled = true; 

        if (!assertsEnabled)
            throw new RuntimeException("Asserts must be enabled!!!");
    } 

Compilation

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

    
    javac -source 1.4 ClassName.java 
This flag is necessary so as not to cause source compatibility problems.

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

To enable assertions at various granularities, use the -enableassertions, or -ea, switch. To disable assertions at various granularities, use the -disableassertions, or -da, switch. You specify the granularity with the arguments that you provide to the switch:

  • no arguments
       Enables or disables assertions in all classes except system classes.
  • packageName...
       Enables or disables assertions in the named package and any subpackages.
  • ...
       Enables or disables assertions in the unnamed package in the current working directory.
  • className
       Enables or disables assertions in the named class

For example, the following command runs a program, BatTutor, with assertions enabled in only package com.wombat.fruitbat and its subpackages:

    java -ea:com.wombat.fruitbat... BatTutor

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

    java -ea:com.wombat.fruitbat... -da:com.wombat.fruitbat.Brickbat BatTutor 

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

To enable assertions in all system classes, use a different switch: -enablesystemassertions, or -esa. Similarly, to disable assertions in system classes, use -disablesystemassertions, or -dsa.

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

    java -esa -ea:com.wombat.fruitbat... 

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

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

Compatibility With Existing Programs

The addition of the assert keyword to the Java programming language does not cause any problems with preexisting binaries (.class files). If you try to compile an application that uses assert as an identifier, however, you will receive a warning or error message. 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:

  • source mode 1.3 (default) — the compiler accepts programs that use assert as an identifier, but issues warnings. In this mode, programs are not permitted to use the assert statement.
  • source mode 1.4 — the compiler generates an error message if the program uses assert as an identifier. In this mode, programs are permitted to use the assert statement.

Unless you specifically request source mode 1.4 with the -source 1.4 flag, the compiler operates in source mode 1.3. If you forget to use this this flag, programs that use the new assert statement will not compile. Having the compiler use the old semantics as its default behavior (that is, allowing assert to be used as an identifier) was done for maximal source compatibility. Source mode 1.3 is likely to be phased out over time.

Design FAQ

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

General Questions

  1. Why provide an assertion facility, 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 culture among engineers using the Java programming language. 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 the Java programming language. 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 the hallmark of the Java programming language. On balance, we came to the conclusion that a simple boolean assertion facility was a fairly straight-forward solution and far less risky. It's worth noting that adding a boolean assertion facility to the language doesn't preclude adding a full-fledged design-by-contract facility at some time in the future.

    The simple assertion facility does enable a limited form of design-by-contract style programming. The assert statement is appropriate for nonpublic precondition, postcondition and class invariant checking. Public 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.

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 implemented a strategy whereby developers can continue using assert as an identifier during a transitional period.

  2. Doesn't this facility produce class files that cannot be run against older JREs?

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

Syntax and Semantics

  1. Why allow primitive types in expression size="1">?

    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 feel like the argument of System.out.println(...), which is seen as desirable.

The AssertionError Class

  1. When an AssertionError is generated by an assert statement in which expression is absent, why isn't the program text of the asserted condition used as the detail message (for example, "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 constructor 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, not just just assertion errors. We enhanced Throwable with the getStackTrace method to provide this functionality.

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

    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 (with @throws doc comments). It makes little sense to include in a method's specification the circumstances under which it may generate an assertion failure. Such information may be regarded as an implementation detail, which can change from implementation to implementation and release to release.

Enabling and Disabling Assertions

  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. Assertions can contain side effects, though they should not, and such a flag could therefore alter the behavior of a program in significant ways. It is viewed as good thing that there is only one semantics associated with each valid Java program. Also, we want to encourage users to leave asserts in object files so they can be enabled in the field. Finally, the spec demands that assertions behave as if enabled when a class runs before it is initialized. It would be impossible to offer these semantics if assertions were stripped from the class file. Note, however, that the standard "conditional compilation idiom" described in JLS 14.20 can be used to achieve this effect for developers who really want it.

  2. Why do the commands that enable and disable assertions use package-tree semantics instead of the more traditional 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 (that is, if the named class has already been initialized)?

    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 name to take the place of setDefaultAssertionStatus and setAssertionStatus?

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

  5. Why not tweak the semantics of desiredAssertionStatus to make it more "programmer friendly" by returning the actual assertion status if a class is already initialized?

    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.

  6. 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 enabling assertions in classes that have yet to be initialized. Moreover, applets can only affect the assert status of classes that are to be loaded by class loaders that the applets can access. There already exists a RuntimePermission to prevent untrusted code from gaining access to class loaders (getClassLoader).

  7. 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. Further, it is straightforward to query the assert status atop the current API, if you feel :

       boolean assertsEnabled = false;
       assert assertsEnabled = true;  // Intentional side-effect!!!
       // Now assertsEnabled is set to the correct value 
  8. Why does an assert statement that executes before its class is initialized behave as if assertions were enabled in the class?


    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.