Assertions - Debugging in J2SE 1.4

by Thomas Paul

Introduction

Assertions are new to Java and are included in the SCJP 1.4 exam. Anyone planning to take the exam should understand the concepts behind the assert keyword. In fact, all Java developers should understand assertions so they can determine if using them can be helpful in their development projects.

In order to make assertions work, a new keyword, assert, has been added to Java. This means that a class written using assertions can not be compiled using older versions of J2SE. It also means that classes compiled with the assert keyword can not be run in earlier versions of the JRE.

What is the purpose of the assert keyword? The purpose of assertions is to test your assumptions about the state of your program during execution. For example, if variable employee should never be null, you can test this assumption and stop your program if it occurs. Assertions are designed to be a development aid. You should not use assertions with the idea of testing conditions during production runs. Your class may be executed with assertions turned off so that if your program relies on assertions to run correctly then it may fail.

The Basics

The simple format of the assert statement is:

     assert BooleanExpression;

The BooleanExpression is any expression that returns either a true or false. Assuming that we are running with assertions turned on, Java will terminate with an AssertionError if this statement returns a false.

The second format of the assert statement is:

     assert BooleanExpression: ValueExpression;

The ValueExpression can be any expression that returns a value. The value (normally a String) will be added to the error message returned when the assertion fails.

Let's look at a very simple program using an assertion.

public class AssertTest
{
	public static void main(String[] args)
	{
		assert false: "This class always fails";
	}
}

This program will always terminate with an AssertionError if assertions are turned on. To compile this program we need to add a parameter (-source) to the compile statement. If we don't add the -source, use of the assert keyword will generate a compile error:

AssertTest.java:5: warning: as of release 1.4, assert is a keyword, and may not be used as an identifier

Here's the javac command to compile our assertion test class:

     javac -source 1.4 AssertTest.java

After successfully compiling, if you want to execute your program with assertions turned on then you must us the -enableassertions (or -ea) switch. To execute our assertion test program we would do the following:

     java -ea AssertTest

This will give us this result:

java.lang.AssertionError: This class always fails
	at AssertTest.main(AssertTest.java:5)
Exception in thread "main" 

Using Assertions

So why do we use assertions? The purpose of an assertion is to test to see if something that should never happen happens! So if we calculate a value and that value should only contain an even number, we can test that assertion and throw an AssertionError if the test fails. For example:

public class AssertTest
{
	public static void main(String[] args)
	{
		int retValue = getEvenNumber(Integer.parseInt(args[0]));
		assert retValue % 2 == 0;
	}

	public static int getEvenNumber(int number) 
    {
		return number * 3;
	}
}

The result of running this class will depend on the input. At times it will run normally and other times it will throw an AssertionError. This gives you an opportunity to test your assumption (the getEvenNumber method always returns an even number) without having to write if...else logic and having to remove the code for production. It also helps to document your assumptions as the next person to work on this class will see that you are asserting that the getEvenNumber method always returns an even number.

However, you do not want to code your programs as if assertions are always turned on. Remember, assertions must be specifically activated at runtime or they will not be executed. As an example, the following code may look like a good way to validate input to your method but it should be avoided.

public class AssertTest
{
	public static void main(String[] args)
	{
		processEvenNumber(Integer.parseInt(args[0]));
	}

	public static void processEvenNumber(int number)
	{
		assert number % 2 == 0;
		// process the input
		return;
	}
}

If the class is executed without assertions being turned on, the validation will not occur. Instead of using assertions for this case, you should use normal if...else constructs. You should use assertions (1) during development and (2) while in production to debug production problems. Testing such as the example above where we are verifying the input prior to executing the method's logic is called precondition verification. Never use assertions for precondition verification unless it is in a private method where you control the input. In that case, you can verify that your code is giving the correct input to your method.

Assertions can be used for postcodition verification in private or public methods. Postcondition verification is where we test the output of our method to insure that the result we are returning is correct. An example of postcondition verification:

public class AssertTest
{
	public static void main(String[] args)
	{
		int retValue = getEvenNumber(Integer.parseInt(args[0]));
	}

	public static int getEvenNumber(int number) 
    {
        int retValue = number * 2;
        assert retValue % 2 == 0;
        return retValue;
	}
}

Another way to use assertions is to test for class invariants. A class invariant is a condition that should always be true about a class. Imagine we have a class representing a deck of cards. Once the class is instantiated it should contain an array of 52 entries each with a different random number between 1 and 52 without duplicates. We can create a method to test this assumption and then execute this method to verify that the class is working correctly. For example:

     DeckOfCards dc = new DeckOfCards();
     assert dc.assertionValidate();

Final Thoughts

Sun has an excellent tutorial on using assertions. You can see it at:

http://java.sun.com/j2se/1.4/docs/guide/lang/assert.html

According to Sun, the runtime cost of using assertions when they are turned off is negligible. This means that we can leave our assertions in our code for production without paying a price for skipping over them. Using assertions should help to improve the quality of the code you produce. We can now test all of our assumptions easily, insuring that our code is as bullet-proof as we think. So give assertions a try.