SECTION 5.10: ASSERTIONS 195
Excerpt from the
forthcoming Second Edition
of
A Programmer’s Guide to
Java Certification:
A Comprehensive Primer
Khalid A. Mughal
Rolf W. Rasmussen
Publisher: Addison-Wesley
http://www.ii.uib.no/~khalid/pgjc/jcbook/
(Dated: 14-January-2003)
5.10 Assertions
Assertions in Java can be used to document and validate assumptions made about
the state of the program at designated locations in the code. Each assertion con-
tains a boolean expression which is expected to be
true
when the assertion is exe-
cuted. If this assumption is
false
, the system throws a special assertion error. The
assertion facility uses the exception handling mechanism to propagate the error.
The assertion facility can be enabled or disabled at runtime.
The assertion facility is an invaluable aid in implementing correct programs, i.e.
programs that adhere to their specification. It should not be confused with the
exception handling mechanism which aids in developing robust programs, i.e. pro-
grams that handle unexpected conditions gracefully. Used judiciously, the two
mechanisms facilitate programs that are reliable.
assert
Statement and
AssertionError
Class
The following two forms of the
assert
statement can be used to specify assertions:
assert
<boolean expression>
; // the simple form
196 CHAPTER 5: FLOW CONTROL, ASSERTIONS AND EXCEPTION HANDLING
assert
<boolean expression>
:
<message expression>
; // the augmented form
If assertions are enabled (p. 199), the execution of an
assert
statement proceeds as
shown in Figure 5.8. The two forms are essentially equivalent to the following code
respectively:
if (
<assertions enabled>
&& !
<boolean expression>
) // the simple form
throw new AssertionError();
if (
<assertions enabled>
&& !
<boolean expression>
) // the augmented form
throw new AssertionError(
<message expression>
);
If assertions are enabled, then <boolean expression> is evaluated. If its value is
true
,
execution continues normally after the
assert
statement. However, if it is
false
, an
AssertionError
is thrown and propagated. In the simple form, the
AssertionError
does not provide any detailed message about the assertion failure.
The augmented form provides a <message expression> which can be used to provide
a detailed error message. In the augmented form, if the assertion is
false
, the <mes-
sage expression> is evaluated and its value passed to the appropriate
AssertionError
constructor. The <message expression> must evaluate to a value, i.e. either a primi-
tive or a reference value. The
AssertionError
constructor invoked converts the
value to a textual representation. In particular, the <message expression> cannot call
a method that is declared
void
. The compiler will flag this as an error.
Lines (2), (3) and (4) in class
Speed
(Example 5.15) are assertion statements. In this
particular context of calculating the speed, it is required that the values fulfil the
criteria in lines (2), (3) and (4) in the private method
calcSpeed()
. Lines (2) and (4)
use the simple form:
assert distance >= 0.0; // (2)
...
assert speed >= 0.0; // (4)
Figure 5.8 Execution of the simple
assert
statement (when assertions are enabled)
Evaluate boolean
expression
[false ]
[true ]
Throw an AssertionError
Normal execution continues.
Execution is aborted and
AssertionError propagated.
SECTION 5.10: ASSERTIONS 197
Line (3) uses the augmented form:
assert time > 0.0 : "Time is not a positive value: " + time; // (3)
Line (3) is equivalent to the following line of code, assuming assertions have been
enabled at runtime:
if (time <= 0.0) throw new AssertionError("Time is not a positive value: " + time);
The
java.lang.AssertionError
class is a subclass of
java.lang.Error
(Figure 5.6). This
makes
AssertionError
exceptions unchecked. They could be explicitly caught and
handled using the
try-catch
construct. The execution would then continue nor-
mally, as one would expect. However, since
Error
exceptions are seldom caught
and handled by the program, the same applies to
AssertionError
exceptions. Catch-
ing these exceptions would defeat the whole purpose of the assertion facility.
In addition to the default constructor (which is invoked by the simple
assert
form),
the
AssertionError
class provides seven single-parameter constructors: six for the
primitive datatypes and one for object references. The type of the <message expres-
sion> used in the augmented assertion statement determines which of the over-
loaded constructors is invoked. It is not possible to query the
AssertionError
object
for the actual value passed to the constructor. However, the method
getMessage()
will return the textual representation of the value.
Example 5.15 Assertions
public class Speed {
public static void main(String[] args) {
Speed objRef = new Speed();
double speed = objRef.calcSpeed(-12.0, 3.0); // (1a)
// double speed = objRef.calcSpeed(12.0, -3.0); // (1b)
// double speed = objRef.calcSpeed(12.0, 2.0); // (1c)
// double speed = objRef.calcSpeed(12.0, 0.0); // (1d)
System.out.println("Speed (km/h): " + speed);
}
/** Requires distance >= 0.0 and time > 0.0 */
private double calcSpeed(double distance, double time) {
assert distance >= 0.0; // (2)
assert time >0.0 : "Time is not a positive value: " + time; // (3)
double speed = distance / time;
assert speed >= 0.0; // (4)
return speed;
}
}
198 CHAPTER 5: FLOW CONTROL, ASSERTIONS AND EXCEPTION HANDLING
Compiling Assertions
The assertion facility was introduced in J2SE 1.4. At the same time, two new
options for the
javac
compiler were introduced for dealing with assertions in the
source code:
•Option
-source 1.4
The
javac
compiler distributed with the Java SDK v1.4 will only compile asser-
tions if the option
-source 1.4
is used on the command-line:
>javac -source 1.4 Speed.java
This also means that incorrect use of the keyword
assert
will be flagged as an
error, for example if
assert
is used as an identifier. The following program
public class Legacy {
public static void main(String[] args) {
int assert = 2003;
System.out.println("The year is: " + assert);
}
}
when compiled, results in two errors:
>javac -source 1.4 Legacy.java
Legacy.java:4: as of release 1.4, assert is a keyword, and may not be used as an
identifier
int assert = 2003;
^
Legacy.java:5: as of release 1.4, assert is a keyword, and may not be used as an
identifier
System.out.println("The year is: " + assert);
^
2 errors
•Option
-source 1.3
The default behavior of the
javac
compiler is equivalent to using the option
-
source 1.3
on the command-line.
>javac -speed 1.3 Speed.java
Speed.java:14: warning: as of release 1.4, assert is a keyword, and may not be used
as an identifier
assert distance >= 0.0; // (2)
^
Speed.java:15: ';' expected
assert distance >= 0.0; // (2)
^
...
9 errors
3 warnings
The compiler will reject assert statements. It will also warn about the use of the
keyword assert as an identifier. In other words, source code that contains the
keyword assert as an identifier will compile (barring any other errors), but it
will also result in a warning. Compiling and running the
Legacy
class above gives
the following results:
SECTION 5.10: ASSERTIONS 199
>javac -source 1.3 Legacy.java
Legacy.java:4: as of release 1.4, assert is a keyword, and may not be used as an
identifier
int assert = 2003;
^
Legacy.java:5: as of release 1.4, assert is a keyword, and may not be used as an
identifier
System.out.println("The year is: " + assert);
^
2 warnings
>java Legacy
The year is: 2003
Runtime Enabling and Disabling of Assertions
Enabling assertions means they will be executed at runtime. By default, assertions
are disabled. Their execution is then effectively equivalent to empty statements.
This means that disabled assertions carry insignificant performance penalty,
although they add storage overhead to the byte code of a class. Typically, assertions
are enabled during development and left disabled once the program is deployed.
Two switches are provided to enable and disable assertions with various granular-
ities in a
java
command. The switch
-enableassertions
, or its short form
-ea
, enables
assertions, and the switch
-disableassertions
, or its short form
-da
, disables asser-
tions at various granularities. The granularities that can be specified are shown in
Table 5.2.
Assertion execution for all non-system classes
The
-ea
option means that all non-system classes loaded during the execution of the
program have their assertions enabled. A system class is a class that is in the Java
platform libraries. For example, classes in the
java.*
packages are system classes.
A system class is loaded directly by the JVM.
Table 5.2 Granularities for enabling and disabling assertions at runtime
Argument Granularity
-ea
-da
Applies to all non-system classes.
-ea:<package name>...
-da:<package name>...
Applies to the named package and its
subpackages
.
-ea:...
-da:...
Applies to the unnamed package in the current working
directory.
-ea:<class name>
-da:<class name>
Applies to the named class.