Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member
0 Kudos
Introduction

The code that we write is full of assumptions: things we believe will be true anytime, anywhere. Assertions are a powerful way to check and document those assumptions. This blog entry is a brief introduction to assertions and their use in the Java language.

What are assertions, anyway?

An assertion statement tests an assumption that you made in your code. Since JDK 1.4, the following two forms of assertion statement have been available in Java:



// Assertion without a detail message
assert expression1;

// Assertion with a detail message
assert expression1 : expression2;

When the assertion statement is executed, the boolean expression expression1 is evaluated. If it evaluates to true, nothing happens. If it evaluates to false, an AssertionError (which inherits from Error and is therefore unchecked) is thrown. The second form evaluates the expression expression2 and passes its value to the constructor of the AssertionError class.

Assertions not only check your assumptions at runtime, they also document them directly in the source code. You might think of assertions as a kind of executable documentation, along with, e.g., unit tests.

Assertions and defensive programming

In a nutshell, defensive programming is about writing code that expects trouble and deals with it. Take a look at the following method from the java.math.BigInteger class:



public BigInteger divide(BigInteger val) {
  // Implementation goes here
}

What happens if we pass the method a BigInteger object representing zero? Bad things, obviously, which is why the method throws an ArithmeticException in that situation. But why not use an assertion like the following?



assert !val.equals(BigInteger.ZERO) : "Expected non-zero value";

First off, assuming that the method will never be passed a value of zero is clearly a very bad assumption (programmers make mistakes, after all). Second, when checking the parameters of a publicly available method for validity, we want to throw exceptions that describe the problem in a meaningful way, such as IllegalArgumentException, NullPointerException, IndexOutOfBoundsException etc. However, assertions make a lot of sense when you're checking the parameters of a nonpublic method for validity. Under those circumstances it's reasonable to assume valid parameter values, since you're the only person calling the method.

Enabling assertions

Assertions must be enabled at runtime with the command-line switch -enableassertions (or -ea for short); they are disabled by default. As a general rule you'll want to have assertions enabled on your development and QA systems and disabled on your production systems. Why is that? While developing and testing, you want to have as much information available as possible. When the code reaches production quality, it's reasonable to expect that the assumptions, which the code is based on, hold water. If the code starts behaving erratically in production, you have the option of turning assertions back on.

The fact that assertions might be disabled on the system where your code runs, has one very important implication: The expressions in your assertion statement cannot make any state changes that your program depends upon for proper operation. Consider the following code snippet:



assert count++ % 2 == 0 : "Count is not even - this shouldn't happen!";

This assertion has the side effect of incrementing the count variable. If assertions are disabled, the variable will not get incremented and the code will probably stop working. Here's a rewrite of the assertion with no side effects:



assert count % 2 == 0 : "Count is not even - this shouldn't happen!";
count++;

Moving the increment operator out of the assertion statement ensures that the count variable will always get incremented, also when assertions are disabled.

3 Comments