Assertion Concept Simplified In Java

Class Class in Java
Assertion in Java

Assertion in java:

In our day to day coding we frequently use System.out.println() statement to debug our code. This is very popular and simple way to debug our development code or test code.One problem of this approach, we can not keep these System.out.println() statement as it is. we need to remove this statement before releasing this code. It is basically overhead for any coder. To overcome this problem Java has come up with a concept called Assertion in java 1.4. prior to java 1.4, in Java 1.3 version it was declared as Identifier.

Design Contract and Assertion:

Design by contract was introduced in Eiffel language. This technique specifies how various components of an application interacts with each others.For this to happen, it defines a contract based on which the components of the application communicate with each other.The DBC technique uses assertions to check whether the application meets the requirements specified in defined contract.
The assertions can be used to test the assumptions made by a programmer in Java.

Ads code goes here

The DBC technique allows a programmer to provide a detailed specification to create a software according to the user requirements.Based on this specification,the programmer develops the application. The DBC technique uses 3 basic types of assertions to check if the application complies with the specification. They are as follows:

  1. Precondition- An application must satisfy this specific condition before calling an internal component.
  2. Post Condition-An application must satisfy this specified condition after the execution of the external component.
  3. Invariant-An application must always satisfy this specified condition.

 

Real time example of Precondition,Post Condition and Invariant:

let us take an example to extract an element from an Array.

The precondition-

Check the Array to see it it is blank or it has some elements. This condition is checked before extracting an element from the Array.

The post condition-

When we push an element to the Array,we need to check if the element is pushed to the Array correctly.

Invariant-

The number of elements in the Array is greater than equal to zero and should not exceed the capacity of the Array.

Implementing the Assertion:

As assertion is a statement , which contains a Boolean expression that the programmer assumes to be true.If the result of the Boolean expression is true the program execution continues.Here , the assertion ensures that the assumptions made by the programmer are correct and free from errors.
If the result of the Boolean expression is false, the AssertionError exception will be thrown.This exception contains the error information such as file name and the line number in which the error has occurred in the code.

The concepts are as follows..

  • The main advantage of assertion is like System.out.println() statement, we don’t need to delete these statements  as they do not get executed by default.
  • Secondly after release if any bug has come to that particular module we need to fix that. Post bug fix or during debugging again we don’t need to enter System.out.println   or Assert statement. It is already available inside the code hence only enabling that will reduce our work.
  • So it exists in development and test instance but not in production environment
  • It is a better alternative for System.out.println statement.
READ  Dangling Else Problem in Java

Let us see more details:

class assertTest
{
public static void main(String[] args)
{
int assert=13;
System.out.println(assert);
}
}

Compiler will throw errors saying:

javac E:myProgramassertTest.java

E:myProgramassertTest.java:5: error: as of release 1.4, ‘assert’ is a keyword,and may not be used as an identifier
int assert=13;
^
(use -source 1.3 or lower to use ‘assert’ as an identifier)
E:myProgramassertTest.java:6: error: as of release 1.4, ‘assert’ is a keyword,and may not be used as an identifier
System.out.println(assert);
^
(use -source 1.3 or lower to use ‘assert’ as an identifier)
2 errors

But if we compile against java 1.3, it will compile fine but with warning.

javac -source 1.3 E:myProgramassertTest.java
warning: [options] bootstrap class path not set in conjunction with -source 1.3
E:myProgramassertTest.java:5: warning: as of release 1.4, ‘assert’ is a keywor
d, and may not be used as an identifier
int assert=13;
^
(use -source 1.4 or higher to use ‘assert’ as a keyword)
E:myProgramassertTest.java:6: warning: as of release 1.4, ‘assert’ is a keywor
d, and may not be used as an identifier
System.out.println(assert);
^
(use -source 1.4 or higher to use ‘assert’ as a keyword)
3 warnings

let us see one more example..

class assertTest
{
public static void main(String[] args)
{
assert(false);
System.out.println(assert);
}
}

For this case if we compile with source -1.3, we will get compiler error. but similarly if we compile against 1.4 or upgraded version of java. We will not get the compilation error.
Conclusion: assert could have been used as an identifier in java 1.2 or java 1.3 and in java 1.4 it was promoted as a keyword.So, now ,java 1.4 onward assert can not be used as an identifier.

Types of Assert:

 

  • Simple like assert Expression1;
  • Augmented like Expression1:Expression2

Simple Assertion:

The syntax for simple assertion is
assert(b)
Where b should be Boolean.
It signifies that up to assert statement if b value calculated as true then rest of the statements (below assert statements will be executed). If the assert value calculated as false then it will throw an AssertionError Exception and terminate the program.
let us check out one sample program

class assertTest{
public static void main(String... args)
{
int a=12;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
assert(a>12);
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
System.out.println(a); 
}
}

The output for this program will be:

javac assertTest.java
java assertTest
output:12
now ..
java -ea assertTest
output:Assertion Error
Exception in thread “main” java.lang.AssertionError
at assertTest.main(assertTest.java:6)
Let us take one more example:


public void division(){
double c=a/b;//b can not be zero
}
//in the above example b can not be zero statement can be replaced by using the 
//assert statement
public void division(){
assert b!=0;
double c=a/b;
}
 

If the expression in the assrt statement is false,it specifies that the program contains errors and this process is referred to as an Assertion failure.

Why -ea is required?

By default the assertions are disabled , but by using “-ea” we are enabling the assertion.

Now if you see the output of the previous program, by seeing the console it is very tough to understand what went wrong.If it is small program then it is ok.We can identify the problem.But think about a scenario where thousands of lines are getting executed.
To get more clarity to the program java has come up with upgrade version of assertion called Augmented version assertion

Augmented Assertion:

So the main advantage of augmented version is that in the console we can append some description with assertion error.
The syntax for the augmented assertion is assert(b):c;
where b is boolean and c can be any data type.c is passed to the constructor of the AssertionError Exception.
Now let us modify our previous program little bit:

class assertTest{
public static void main(String... args)
{
int a=12;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
assert(a>12):"The value of a should be greater than 12";
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
System.out.println(a); 
}
}

javac assertTest.java
java assertTest
output:12
now ..
java -ea assertTest
The output:
Exception in thread “main” java.lang.AssertionError: The value of a should be greater than 12
at assertTest.main(assertTest.java:6)
So we are getting bit more clarity from the code.
Let us take one more example:


assert age>0:"The age of a person should not be less than zero"
 

Here age>0 is a Boolean expression.The second expression in the assert statement is a String value and it is passed to the constructor of the AssertionError Exception. If the assertion failure occurs, the string value acts as an additional information about the error.

READ  Array Concept Simplified in Java

Augment Assertion Rule-1

For this augmented assertion if the first argument is true(value of b)then the second argument c(some string output for this case) will not be evaluated.

lets see that:

class assertTest{
public static void main(String... args)
{
int a=12;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
assert(a==12):++a;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
System.out.println(a); 
}
}

javac assertTest.java
java assertTest
output:12
now ..
java -ea assertTest
output:12
This time the assertion passed hence ++a was not executed .

Now let us see the same example by failing the assertion condition …this time b fails so c should get executed

class assertTest{
public static void main(String... args)
{
int a=12;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
assert(a>12):++a;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
System.out.println(a);
}
} 

javac assertTest.java
java assertTest
output:12
now ..
java -ea assertTest
output:Exception in thread “main” java.lang.AssertionError: 13
at assertTest.main(assertTest.java:6)

So a value is now incremented by one and got printed.

Augment Assertion Rule-2

The second argument c can be a method call,and very logically that method should not be a void type.

So the syntax should be assert(b):method_name();
let us check out via code:

class assertTest{
public static void main(String... args)
{
int a=12;
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
assert(a>12):methodxyz();
//do some calculation
//do some calculation
//do some calculation
//do some calculation
//do some calculation
System.out.println(a);
}
public static int methodxyz()
{
return 65;
}
} 

javac assertTest.java
java assertTest
output:12
now ..
java -ea assertTest
output:Exception in thread “main” java.lang.AssertionError: 65
at assertTest.main(assertTest.java:6)

Now if we change the return type of that function as void , we are going to get compile time error.
The error details:
E:myProgramassertTest.java:6: error: ‘void’ type not allowed here
assert(a>12):methodxyz();
^
1 error

Various Possible Runtime Flags

Let us check what are the flags available–

FlagsDescription
-ea/-enableassertionsTo enable assertion in every non-system classes
-da/-diaableassrtionsTo disable assertion in every non-system classes
-esa/-enablesystemassertionsTo enable assertion in every system classes
-dsa/-deletesystemassertionsTo disble assertion in every non-system classes

In general normal java developers use assertion for non-system classes and java-API developers use assertion for system classes.
we can use the above flags simultaneously then JVM will consider these flags from left to right.
java -ea -esa -da -ea-esa-da -dsa -ea testAssert
the above written syntax is valid.
Let us check out few more examples:

In our real time coding we might require to enable assertion against customized classes .
if our package structure is the picture above then..

ObjectiveRequired Code
To enable assertions only for B classjava -ea:package1:B
To enable assertions only in B and D classesjava -ea:package1:B -ea:package1.package2.D
To enable assertion everywhere inside package1 except B classjava -ea:package1… -da:package1.B
To enable assertion everywhere inside package1 except package2 classesjava -ea:package1… -da:package1.package2…
To enable assertions everywhere inside package1java -ea:package1…

Conclusion:

So we can enable or disable assertions classwise or package wise.

Difference between Exception and Assertion:

Exception is used to test the abnormal conditions,such as division by zero, ArrayOutOfBoundsException. They occur during program execution and does not ensure that the code is running correctly.

Assertion is used to test the condition assumed by the coder and it ensures that the code is running correctly.

READ  All About Class BufferedInputStream in Java

Generic Assertion rules:

Assertion is used to check the validity of an assumption(made by the coder).The rule that govern the assertion are as follows:

  • Check the method argument.
  • Use assertion in the default case of a switch statement
  • Make use of assertion description.
  • Avoid processing in an assertion condition.
  • Avoid catching assertion related exceptions.
  • Avoid the use of evaluating more than one condition in the assertion.

Checking the method argument:

Lets take an example here:


public void add(int a,int b)
{
int c=a+b;
}
 

The user has specified that the function executes only for all positive values of a and b. so if the user provides negative values of a or b the result is inaccurate. So the modified code will be:


public void add(int a,int b)
{
if((a>0)&&(b>0))
{
int c=a+b;
}
}
 

Avoid evaluating more than one condition in an assert statement:

If we use more than one condition in an assert statement , it may be difficult to find which of the condition is not satisfied.


public void setName(String firstName,String lastName)
{
if((firstName==null)||(lastName==null))
{
throw new IllegalArgumentException("First Name or Last Name can not be null");
}
}
//equivalent assert code:
public void setName(String firstName,String lastName)
{
assert((firstName==null)&&(lastName==null)):"First Name or Last Name can not be null";
}
 

in the above code if one condition fails,it is difficult for the programmers to identify which is the assumption went wrong and causes failure.Hence the above code can be written as:


public void setName(String firstName,String lastName)
{
if((firstName==null)
{
throw new IllegalArgumentException("First Name can not be null");
}
if(lastName==null)
{
throw new IllegalArgumentException("Last Name can not be null");
}
}
//equivalent assert code:
public void setName(String firstName,String lastName)
{
assert(firstName==null):"First Name can not be null";
assert(lastName==null):"Last Name can not be null";
}
 

When we compile and run the program,the assert statement is checked.If the assertion failed, the control will be transferred to Exception in the assert statement.The control will not be transferred to next statement. This how assertion guarantees the assumption to be true.

Do’s and Don’ts While Working With Assertions In Java:

Now in this post let us check out few rules and best practices to work with assertion.

Let us follow few common rules:

Do not mix business logic/programming logic with Assertion. As assertion will not run always until assertion is enabled.
Good coding practice:

amount_withdraw(int amount)
{
//some validation
if((amount<100 || amount>=5000))
System.out.print("This amount can not be deducted");
else
//let user deduct the amount
}

Bad coding practice:

amount_withdraw(int amount)
{
//some validation
assert(amount>=100)||assert(amount<5000)
//let the user allow to get data
}

During debugging,in our program, the best place to put assertion where control does not reach or not allowed to reach.
Good coding practice:

switch(month_val)
{
case 1: System.out.println("Jan");break;
case 2: System.out.println("Feb");break;
case 3: System.out.println("Mar");break;
......
......
case 12: System.out.println("Dec");break;
default: assert(false);
}

This is not violating 1st rule ..if the month value is anything other than 1 to 12.We need to check. Hence it is valid.

 

  • It is a bad practice to use assertion inside public method.As the public methods will be accessed by outside coders and method consumers, they will not be knowing whether to enable or disable assertion.
  • Secondly it is always good to have assert for private method as the method designer is local and can check the assertion
  • Thirdly, this not good to put assert while validating command line argument. This can be argument of public main method.(Please refer here for more)

Let us check with some example.

class assertTest{
public static void main(String... args)
{
asset(args.length<5):"Need more inputs";
}
}

 

  • All the assertion errors are child class of Error. Super class Error is unchecked during compile time hence assertion error will be unchecked.
  • All the assertion errors will be raised when the assertion will fail during run time
  •  It is legal to catch assertion error but the objective of assertion is to fail if something is not as per programmer’s expectation.So it is not recommended to use.(Please refer here for more)
class assertTest{
public static void main(string... args)
{
int a=12;
-----
-----
-----
try
{
assert(a>12);
}
catch(AssertionError e)
{
//some code
}
}
}

Share and Enjoy !

Leave a Comment

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