4.6. AssertionsAn 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). Explicit support for assertions was added in Java 1.4. However, if you've written much code in any language, you have probably used assertions in some form. For example, 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 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 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). Java 5.0 supports assertions natively. In Java 1.4 (the previous version in this crazy numbering scheme), code with assertions requires a compile-time switch: % javac -source 1.4 MyApplication.java 4.6.1. Enabling and Disabling AssertionsAssertions 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, then turns exceptions on for just one class, MonkeyTypewriters, in that package. 4.6.2. Using AssertionsAn 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 cannot 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, containing 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 assertionsall 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 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. |