Java Assertions
Assertions are one of the most useful debugging tools around but from what I have seen using them may not be common Java practice. There are several probable reasons for this:
-
assertions came late on the scene only being added to the language in J2SE 1.4.
-
control over assertions is a function of a JVM switch not a compiler option. This means that generated code for asserts is included in a deploy build whether or not it is required. (there are ways around this: [jGuru] [Java.net], but nothing particularly inviting unless you want to make your code look like something out of the C++ STL)
-
Java provides a detailed but comprehensible stack trace when an exception is thrown making error root cause much easier to identify than in some other languages, at least until comparatively recently.
A Java assertion has the form
assert <boolean expression> : <problem>;
with the : <problem> part being optional. If the boolean evaluates to false and the JVM -ea switch is set a java.lang.AssertionError is thrown with <problem> as its message. <problem> is an expression that evaluates to anything other than void, generally a String.
To set assertions on in NetBeans, right click on the project node and select Properties. Choose Run from the tree and type -ea in the VM Options edit. Alternatively you can click [Customize] and check ea in the list. warning: running from NetBeans part of an AssertionError message may be missing in the output window.
Assertions allow preconditions, post-conditions and invariants to be checked by code that is optionally executed by the JVM bringing these aspects of formal methods (basically VDM) into as-coded reality. Java method specifications are referred to as contracts making contract verification seem quite appropriate. The Java article [here] provides a comprehensive review.
For example: if n < 0, the Math.squrt(n) function returns a Not a Number (NAN) without throwing an exception. NANs have some fairly strange and probably unwanted characteristics when used in computations so we could write our own square root that checks for this problem:
public static double asqrt(double n) { // pre-condition assert (n >= 0) : n + ": no real sqrt"; return Math.sqrt(n); }
NetBeans is not clever enough to include the -ea option in its suggested command-line invocation. It must be inserted by hand to run an app. with assertions from a terminal window e.g:
F:\>java -jar -ea "F:\PROGRAMMING PROJECTS\NetBeans\Tests\Assert Test\dist\Asser t Test.jar Exception in thread "main" java.lang.AssertionError: -1.0: no real sqrt at pkgassert.test.Asserts.asqrt(Asserts.java:14) at pkgassert.test.AssertTest.main(AssertTest.java:17) F:\>
When turned off in the JVM assertions get no runtime overhead apart from a conjectured increase in the time taken to load bigger classes. Admittedly control over their execution is not all it might be but for a small fee and given maybe a day to make it look pretty, I could write a Delphi GUI app. providing navigation to a project directory or to any sub-directory or file that would walk the file tree and strip or remark out assert statements in any java files encountered. Wonder why the Java gurus haven't produced a Java app. to do just that?
Comments
New comment
I suppose that it comes down to your programming style as to whether you use these. Personally I prefer to rely on the contract.
Let's take the square-root static method as an example.
I agree that returning NaN isn't a good solution. In fact I think that it's possibly the worst solution. Things could get flakey if tests aren't made, and Java is supposed to be strongly typed!
You have to ask, where do you want to catch the problem? Compile time or runtime?
assert is good for catching errors at compile time, but my guess is that is that most of these errors are going to be caused by dodgy user input, in which case an assert wouldn't help.
My personal preference would be to make the calling Object decide what it wanted to do with an illegal argument by making the method throw a checked runtime exception. Although I'd hope that the calling Object would respect the contract do it's own validation, but that's the point of checked exceptions—forces people to think!
neil
New comment
Hi Neil - thanks for your comments, interesting. Maybe I didn't explain things too well. In fact Java assertions in a method provide a runtime check that its contract has been complied with: by the callers of the method - preconditions check actual parameters passed comply, and by the method itself - post conditions check results comply, getting 'design by contract'.
It is C++ that has the static_assert() compile-time assertions. It needs them to check that different variable sizes and/or constants introduced by conditional compilation or instantiations of its recompiled template classes do not introduce a disaster scenario - neither problem applies to Java.
The difficulty with making trivial functions (like sqrt maybe), that can be called many times to meet a single requirement, throw an exception is the overhead from the trap code that checks for the error. The advantage of assertions is that this overhead can easily be removed without code modification when an application is stress tested and when it is deployed. Hopefully this gets the best of both worlds.
In many languages assertions provide a cleaner, more comprehensible way of introducing runtime checks than conditional compilation: $IFDEF DEBUG .... $ENDIF all over the place for example. In Java they are all that is available to meet differing testing / deploy requirements. The Java assertion downside for more general usage is that they are either on or off across an application. You can't build part of an application and test it to destruction with assertions on and then compile it without assertions except by deleting the asserts.