Assertions

An assertion is a simple pass/fail test of some condition, performed while your application is running. Assertions can be used to “sanity check” your code anywhere you believe certain conditions are guaranteed by correct program behavior. Assertions are distinct from other kinds of tests because they check conditions that should never be violated at a logical level: if the assertion fails, the application is to be considered broken and generally halts with an appropriate error message. Assertions are supported directly by the Java language and they can be turned on or off at runtime to remove any performance penalty of including them in your code.

Using assertions to test for the correct behavior of your application is a simple but powerful technique for ensuring software quality. It fills a gap between those aspects of software that can be checked automatically by the compiler and those more generally checked by “unit tests” and human testing. Assertions test assumptions about program behavior and make them guarantees (at least while they are activated).

If you have programmed before, you may have written something like the following:

    if ( !condition )
        throw new AssertionError("fatal error: 42");

An assertion in Java is equivalent to this example, but is performed with the assert language keyword. It takes a Boolean condition and an optional expression value. If the assertion fails, an AssertionError is thrown, which usually causes Java to bail out of the application.

The optional expression may evaluate to either a primitive or object type. Either way, its sole purpose is to be turned into a string and shown to the user if the assertion fails; most often you’ll use a string message explicitly. Here are some examples:

    assert false;
    assert ( array.length > min );
    assert a > 0 : a  // shows value of a to the user
    assert foo != null :  "foo is null!" // shows message "foo is null!" to user

In the event of failure, the first two assertions print only a generic message, whereas the third prints the value of a and the last prints the foo is null! message.

Again, the important thing about assertions is not just that they are more terse than the equivalent if condition, but that they can be enabled or disabled when you run the application. Disabling assertions means that their test conditions are not even evaluated, so there is no performance penalty for including them in your code (other than, perhaps, space in the class files when they are loaded).

Enabling and Disabling Assertions

Assertions are turned on or off at runtime. When disabled, assertions still exist in the class files but are not executed and consume no time. You can enable and disable assertions for an entire application or on a package-by-package or even class-by-class basis. By default, assertions are turned off in Java. To enable them for your code, use the java command flag -ea or -enableassertions:

    % java -ea MyApplication

To turn on assertions for a particular class, append the class name:

    % java -ea:com.oreilly.examples.Myclass  MyApplication

To turn on assertions just for particular packages, append the package name with trailing ellipses (. . .):

    % java -ea:com.oreilly.examples...MyApplication

When you enable assertions for a package, Java also enables all subordinate package names (e.g., com.oreilly.examples.text). However, you can be more selective by using the corresponding -da or -disableassertions flag to negate individual packages or classes. You can combine all this to achieve arbitrary groupings like this:

   % java -ea:com.oreilly.examples... 
   -da:com.oreilly.examples.text-ea:com.oreilly.examples.text.MonkeyTypewriters
   MyApplication

This example enables assertions for the com.oreilly.examples package as a whole, excludes the package com.oreilly.examples.text, and then turns exceptions on for just one class, MonkeyTypewriters, in that package.

Using Assertions

An assertion enforces a rule about something that should be unchanging in your code and would otherwise go unchecked. You can use an assertion for added safety anywhere you want to verify your assumptions about program behavior that can’t be checked by the compiler.

A common situation that cries out for an assertion is testing for multiple conditions or values where one should always be found. In this case, a failing assertion as the default or “fall through” behavior indicates the code is broken. For example, suppose we have a value called direction that should always contain either the constant value LEFT or RIGHT:

    if ( direction == LEFT )
        doLeft();
    else if ( direction == RIGHT )
        doRight()
    else
        assert false : "bad direction";

The same applies to the default case of a switch:

    switch ( direction ) {
        case LEFT:
            doLeft();
            break;
        case RIGHT:
            doRight();
            break;
        default:
            assert false;
    }

In general, you should not use assertions for checking the validity of arguments to methods because you want that behavior to be part of your application, not just a test for quality control that can be turned off. The validity of input to a method is called its preconditions, and you should usually throw an exception if they are not met; this elevates the preconditions to part of the method’s “contract” with the user. However, checking the correctness of results of your methods with assertions before returning them is a good idea; these are called post-conditions.

Sometimes determining what is or is not a precondition depends on your point of view. For example, when a method is used internally within a class, preconditions may already be guaranteed by the methods that call it. Public methods of the class should probably throw exceptions when their preconditions are violated, but a private method might use assertions because its callers are always closely related code that should obey the correct behavior.

Finally, note that assertions can not only test simple expressions but perform complex validation as well. Remember that anything you place in the condition expression of an assert statement is not evaluated when assertions are turned off. You can make helper methods for your assertions that may contain arbitrary amounts of code. And, although it suggests a dangerous programming style, you can even use assertions that have side effects to capture values for use by later assertions—all of which will be disabled when assertions are turned off. For example:

    int savedValue;
    assert ( savedValue = getValue()) != -1;
    // Do work...
    assert checkValue( savedValue );

Here, in the first assert, we use the helper method getValue() to retrieve some information and save it for later. Then, after doing some work, we check the saved value using another assertion, perhaps comparing results. When assertions are disabled, we’ll no longer save or check the data. Note that it’s necessary for us to be somewhat cute and make our first assert condition into a Boolean by checking for a known value. Again, using assertions with side effects is a bit dangerous because you have to be careful that those side effects are seen only by other assertions. Otherwise, you’ll be changing your application behavior when you turn them off.

Get Learning Java, 4th Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.