The Object Oriented paradigm is influenced by the design by contract
principal, wherein, the creator and the consumer mutually agree to follow
certain rules. The design by contract theory states that an application is
created or designed according to a contract or specification agreed upon by the
creator and the consumer about the functioning of the application. Assertions
provide a mechanism for implementing the design-by-contract principal.
Assertions were introduced in early programming language like Eiffel and has
been around since 1967. Assertions are not new to Java either. They were a part
of Oak, an early version of JPL (Java Programming Language), but were dropped
from the final draft.
What are Assertions?
Put simply, Assertions are a facility provided within the Java programming
language to test the correctness or assumptions made by your program.
An assertion checks a Boolean-typed expression that a developer specifically
proclaims must be true during program runtime execution. An assertion has a
Boolean expression that, if false, indicates a bug in the code. The checks could
be for assumptions about numbers being negative or being within or outside a
certain range. Assertions are the outcome of JSR 41, and allow programmers to
describe intended program behavior, which can be checked at runtime to detect
bugs.
|
Assertions vs Exceptions
Many developers confuse Assertions with Exceptions. Although some argue that
Java has a built-in exception-handling support, there is still a need to provide
a second alternative for checking program behavior. Exceptions handle abnormal
conditions arising in the course of the program; however, they do not guarantee
smooth or correct execution of the program.
Assertions, on the other hand, help state scenarios that ensure that the
program is running smoothly. In fact, assertions are not supposed to replace
exception handling but augment them. However at runtime, Assertions behave much
like exception handling. When an assertion fails, the program would throw an
AssertionError on to the stack trace. Another difference between Assertions and
Exceptions is that Assertions are 'Errors'. The AssertionError class extends
from the Error class.
Therefore, Assertions are Errors and unlike Exceptions (checked exceptions),
they don't need to be wrapped in a try-catch block. Further, Assertions are
flexible, they can be easily turned on and off by passing some command-line
options. Exceptions define erroneous conditions which are predictable or
reasonable enough for the program to catch and handle. Also, with Exceptions it
is considered a good programming practice to catch more specific exceptions. An
AssertionError, on the other hand, is very general, not very self-documentary or
specific to the error condition.
The output (assertive program behavior) you get by running the same program while Assertions are disabled and enabled |
Using Assertions
An assert statement has two permissible forms. The first one is:
assert expression1;
This statement tests the Boolean expression. It does nothing if the Boolean
expression evaluates to true. However, if the Boolean expression evaluates to
false, this statement throws an AssertionError.
The second form of the assert statement is quite similar to the first one,
except one difference:
assert expression1 : expression2;
This form acts just like the first form. In addition, if the Boolean
expression evaluates to false, the second expression is used as a detail message
for the AssertionError. The second expression may be of any type except void.
The second form adds flexibility, because it allows creating an overloaded form
of AssertionError constructor, and dumping it on the stack trace.
Implementation
To demonstrate Assertions in Java, we'll look at an example of how a heating
engine is designed by a statutory body, which adheres to all compliance. Then
the design is passed on to a contractor for giving a practical shape to the laid
norms. We'll assume that the heat level is set at 600 degrees Fahrenheit.
Assertions can be made at the following stages:
Pre-condition: A condition that the caller of an operation agrees to
satisfy. That is, pre-conditions are values or parameters passed to a method, to
be used for the functioning of the program. The assert statements can be used to
check the validity of the parameters passed before they get used in the body of
the method. The following code snippet shows an assertive behavior.
abstract class HeatingEngine {
public final static double MAX_
TEMPERATURE = 600.0; //max limit
protected double heat_level;
public final void increase_temperature(double amt ) {
if( ( heat_level + amt ) > MAX_TEMPERATURE )
increase_temperatureImpl( MAX_TEMPERATURE - heat_level );
else
increase_temperatureImpl( amt );
assert ( heat_level <= MAX_TEMPERATURE ) : "Max
Heating Level Overflow";
}
protected abstract void increase_temperatureImpl( double amt );
public final double getHeat_level() {
return this.heat_level;
}
}
Here, we set a pre-condition for the contractor to abide by the prescribed
temperature limit. If this is violated, an AssertionError is propagated at
runtime.
Post-condition: If the computation is successful, we say that the
computation has satisfied the post-condition. A post-condition needs to be
evaluated before each exit point in the method.
In our example, if the sum total of the passed parameter to the
increase_temperature() method and existing heat level is below the permissible
limit, the program flow enters in post-condition phase. The contract is
implemented by a contracted, as shown in the following code fragment.
class EvilContractor extends HeatingEngine {
protected void increase_temperatureImpl( double amt ) {
this.heat_level = 1200.0;
}
}
It's pretty evident from the above code snippet that it is easy to breach
the contract, as the contract can easily mutate on the values of inherited
properties. Thanks to Assertions, such potential bugs can be caught early in the
development cycle. The following code snippet shows the runtime calls to the
methods carrying the application logic.
public class AssertDemo {
public static void main( String<> args ) {
HeatingEngine engine = new
EvilContractor();
// increasing the heating level to 100.0 Fahrenheit
engine.increase_temperature(100.0 );
System.out.println( "The current heat level is: " +
engine.getHeat_level());
// increasing the heating level to 100.0 Fahrenheit
engine.increase_temperature(100.0 );
System.out.println( "The current heat level is: " +
engine.getHeat_level());
}
}
Compile and run
Since Assertions is a new feature in Java SE 4, you need an SE 4 SDK to
compile your assertion-friendly programs. Working with assertions is easy,
assertive program behavior can be configured while running applications. To
compile Java source code with assertion enabled, used the following command.
javac -source 1.4 AssertDemo.java
For backward compatibility, by default, assertions are disabled during
runtime in the new JDK 1.4 runtime. Java allows you to enable assertions through
a command line parameter —enableassertions or —ea during runtime, as shown
below:
java —ea AssertDemo
Conclusion
As part of the Java Community Process, JSR (Java Specification Request) 41
proposed adding a simple assertion facility to Java SE Platform. Assertions can
be used within programs to make sure the program behaves in a predetermined
manner and will throw an error when violated.
An important thing to note about the assertion facility is that it is not
provided as a user-level class library. Rather, it is built into the language by
introducing a new keyword statement to JPL (Java Programming Language)-assert.
Assertions are excellent for documenting assumptions and invariants about a
class.
As a good programming practice, assert statements should not be used to check
parameters of a public method. Also, Assertions must be disabled in production.
Although you can, you must never attempt to catch an assertion error or any form
of java.lang.Error.
Assertions are used to test programmer's assumption about a certain
condition in the program. They give you a chance to catch errors during the
program development and correct them to prevent serious programming errors from
leaking into production code.
Kunal Jaggi