Java Assertions

Java assertions. Image of a hand holding a magnifying glass over code with the keyword assert

In the last three posts, we looked at a few different ways to walk a file tree. Let’s leave file walking behind, and look at a rarely used, but very useful feature of the Java language, namely assertions.

Java 1.4 introduced assertions with the keyword assert.

What is an assertion?

An assertion is a statement that lets us test any assumptions that we have about our code.

Let’s say we have to write a method that calculates the square root of a number. To test that it won’t fail, we might want to assert that the number is not negative. To test that it works properly we might want to check that we get the original number when the resulting square root is multiplied by itself.

Writing assertions is a fast, easy way to discover incorrect application behaviour. Assertions can be used to document the inner workings of a program. This helps make the application more maintainable.

Assertions are useful in many places where we would have added comments to document that something should, or shouldn’t, happen. For example, if we’ve left out a default case in a switch statement because the program can’t possibly get there normally. Or we’ve assumed a variable should have a constant value and we’ve coded with that in mind.

The assertion statement supports an informal approach to the Design by Contract methodology. With Design by Contract we first define what our method is supposed to do, and then we verify its behaviour by testing it during execution. We can test preconditions, post-conditions and invariants with assertions.

Using assertions can increase the size of our code slightly, but in the end we can often deliver a product in a much shorter development time. The earlier we can fix bugs, the lower the development cost. Using assertions doesn’t guarantee bug-free code, but it gets us closer to it than code without assertions.

These assertions are very different to the JUnit testing framework assertXxx() methods. That will be the topic of a future post.

Assertion Syntax

Each assertion contains and tests a boolean expression that we believe to be true when the assertion executes. If the expression evaluates to false, the system throws an AssertionError. If the expression is true, then the program continues normally. The assertion confirms any assumptions we may have about the program behaviour. This increases our confidence that there are no errors in our application.

The assertion statement has two forms. The first form is the simplest:

assert boolean_expression;

When the system executes the assertion, it evaluates the boolean_expression. If it is false, an AssertionErroris thrown with no detail message.

The second form of the assertion statement is:

assert boolean_expression : value_expression;

The value_expression is an expression that evaluates to a value (not void). The value is converted to a string that is passed as the detail message to the AssertionError constructor. This is like the way we usually create exceptions with detail messages. We often just use a String message as the value.

The message gives more information on why the assertion failed. This will then help us diagnose and fix the problem. The assertion message is meant for the developers, not for the users. We must always interpret the assertion message in the context of a full stack trace.

Assertions should never be triggered in production code. They are for the development/debug/test parts of the production lifecycle. Assertions point to bugs or a misuse of a code path. An AssertionError indicates unrecoverable conditions in an application. We must never try to handle them or attempt recovery.

Assertion Examples

The following simple example shows how we can use an assertion in the default case of a switch statement:

default: assert false : "Unknown value";

Another way could be to throw an AssertionError. This will give protection even if assertions are disabled:

default: throw new AssertionError("Unknown value");

Here’s another example. We often write code like the following:

Connection conn = DriverManager.getConnection();
if (conn == null) {
    throw new RuntimeException("Connection is null.");
}

Using assertions, we can change the code to:

Connection conn = DriverManager.getConnection();
assert conn != null : "Connection is null.";

Enabling Assertions

By default, assertions are disabled at runtime. Disabling assertions largely eliminates their performance penalty. There are still some small performance issues related to optimization of JIT inline compiled code.

We use the JVM command-line options/switches to enable or disable assertions:

  • To enable assertions, use -ea or –enableassertions.
  • To disable assertions, use -da or -disableassertions.
  • To enable assertions in system classes, use –esa or -enablesystemassertions.
  • To disable assertions in system classes, use –dsa or –disablesystemassertions.

We can pass additional arguments to the options to specify different levels of granularity. We can enable or disable assertions in all classes except system classes; for classes in the named package and any sub-packages; for classes in the unnamed package; and in the named class.

For further information, consult the Java tools documentation.

Best Practices

The most important thing to remember is that assertions can be disabled at runtime. We must never assume that they will always be executed. We must never use an assertion to do anything that our application needs to operate correctly.

Keep the following in mind when using assertions:

  • Always check for null values and empty Optionals where appropriate.

  • Avoid using assertions to check inputs into a public method. Rather use an unchecked exception such as IllegalArgumentException or NullPointerException.

  • Don’t call methods in assertion conditions. Rather assign the result of the method to a local variable and use that variable with assert.

  • Assertions are good for sections in code that will never be executed, such as the default case of a switch statement or after a loop that never ends.

Conclusion

Have you used assertions to check your code? Did it make it easier to write your application? Please share your comments on the blog post.

Stay safe and keep learning!

Leave a Comment

Your email address will not be published. Required fields are marked *

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.