Exception Handling Techniques in Java

Exception handling is one of those programming techniques that beginners often neglect to implement. However, when they end up working on a large project on which dozens of other colleagues are working, they find that you just can’t afford to be superficial. Throughout this article we’re going to cover exceptions, explain what they are, how to work with them, and why they are important—ultimately, how to handle them.

All right, let’s begin explaining what exceptions are. Just as in other programming languages, this applies to Java as well: exceptions are those errors that occur during runtime. These aren’t real errors, because they are exceptions. One might call them exceptional events that can and should be handled to continue program execution. So there’s "something" one has to do about them.

One of the most remarkable examples of exceptional cases and conditions is when, during program execution, the time comes for a division by zero. This cannot be done and, therefore, Java throws an exception, specifically the ArithmeticException. From the Java programmer’s point of view, exceptions are objects. Throwing exceptions is akin to throwing objects. But here’s the drill: not every object can be thrown.

In order to fully understand throwable exceptions, some parts of the entire class hierarchy should be presented. There is one main class called Throwable. This class has two sub-classes: Exception and Error. An exception object must be descended from a class that is Throwable, meaning it must be an object instance of either an Exception sub-class or Error sub-class. These can both be found in the java.lang package.

Exception handling is the technique of catching the exceptions that might be thrown some time in the future during runtime. Java offers robust exception handling solutions with the try-catch-finally construct. On other hand, you can work with already-declared exceptions, such as the ArithmeticException, NullPointerException, and others. Other classes extend the Exception class-e.g., the IOException subclass from java.io

Furthermore, we should also note that exceptions are of two kinds: unchecked and checked. Unchecked exceptions are technically RuntimeExceptions (or its subclasses). These don’t need to be declared in your throws clauses, and catching them is optional, but many don’t bother-they occur without the knowledge of programmers, who may not even know that those are "catchable." Most of the time, these are logic programming errors such as NullPointerException or ArrayIndexOutOfBounds.

Meanwhile, checked exceptions technically force the programmer to handle and manage them, meaning catch and cover them individually. These are derived from the Exceptions class and its subclasses, excluding the RuntimeExceptions as we discussed in the paragraph above (those are unchecked!). Checked exceptions require exception handling because they might cause program termination.

Now that we’ve learned the basic theory, let’s fire up our IDE, and start coding! 

{mospagebreak title=Exception Handling} 

On the previous page we mentioned that exception handling either deals with the exception in the code snippet where it occurs with the try/catch block, or throws the exception back to the runtime engine, which on its end will search for the exception handling routine that is the closest to the place where the exception occurred. It searches within the call stack that contains the sequence of method calls.

Generally, exceptions can happen due to either having an abnormal event that leads to an exceptional case, or another method has thrown the exception and now it’s time to deal with it, or in the case of an asynchronous exception (which happens only when multiple threads are used and they aren’t synchronized appropriately). Now we are going to cover the basics of exception handling: how to "catch" and deal with them.

Java allows us to create our own Exception objects and classes-but there is a critical requirement. They must be extending the Exception class, and that’s how inheritance happens. It is part of the coding standard that exceptions must be named quite "thoroughly," meaning their name should speak for themselves.

throw new Exception(" This is an exception! ");

 

Now let’s see how to catch and deal with an exception. Check out the following.

 

try {

// this is the block of code where the exception happens

// sometimes called as source/root of exception

// or even called as tricky block or tricky method

}

 

catch (Exception_Type1 e){

// dealing with this kind of exception

}

catch (Exception_Type2 e){

// dealing with this kind of exception

}

// … unlimited number of catches are possible

finally {

// this block of code is always executed

}

 

The first part of the try-catch-finally construct is the try block. This is the segment where the exception may occur. Generally it’s advised to write the minimum amount of code lines here since they are executed only until the exception happens. When it does, the execution jumps to the catch blocks, where the exception types are compared. If they match, then the exception that occurred is dealt with. 

The finally block is always executed, regardless of whether or not an exception happens during the try block, or whether an exception could be handled within the catch blocks. Since it always gets executed, it is recommended that you do some cleanup here. Therefore, as expected, implementing the finally block is optional.

The structure of try-catch blocks is similar to that of switch-case constructs. It should also be said that, in the case of checked exceptions, which must be dealt with, it is possible to either "handle" them right where they occur inside that same method, or throw them further. The latter can be done with the throws keyword. And in this case, the type of exception must be specified in the method signature. See the example:

void myMethod () throws SomeKindOfException{

// method goes here

}

 

On the next page we’re going to present some more applicable examples. 

{mospagebreak title=More Exception Handling Examples}

Beginners often struggle with non-matching data types. Frequently they cause problems, such as the occurrence of non-numeric types during addition. In the following code snippet we will present a workaround to this with exception handling. Check out this website for the complete list of built-in Exception types. Right now, we’re going to deal with NumberFormatException occurrences.

public static void main (String args[]) {

double sum = 0;

for (int i = 0; i < args.length; ++i)

try {

sum += Double.parseDouble (args[i]);

}

catch (NumberFormatException e){

System.out.println(args[i] + " non-numeric data on");

}

System.out.println("Total sum: " + sum);

}

 

As you can see, it works with command line arguments, and once a non-numeric argument is reached, it is just written to the standard system out, specifying what’s wrong. But the program goes on, since the try block is within a for loop. Otherwise, without proper exception handling, the program would be terminated. This way the sum is still calculated and printed out at the end.

Let’s present another example. Here we are going to build our own exception class that extends the parent Exception class. The application will simulate the way a stack mechanism works with exception handling, throwing and dealing with exceptions such as Stack is full (and you want to add more elements into the stack) or Stack is empty (and you want to pop elements from the stack). Check it out.

public class StackException extends Exception {

public StackException (String text) {

super (text);

}

}

 

Now let’s create the Stack class itself. Pay attention to the push and pop methods. They are throwing the StackException type of exception, and this is introduced within the method signature. Moreover, there’s an if condition, and the exception is thrown if it’s satisfied. Otherwise, everything just happens smoothly.

 

public class Stack {

private final int SIZE = 100;

private Object st[];

private int size;

private int sp;

 

public Stack (int size) {

if (size < MAXSIZE)

this.size = size;

else

this.size = MAXSIZE;

this.st = new Object [size];

this.sp = -1;

}

 

public void push (Object o) throws StackException {

if (sp == this.size – 1)

throw new StackException ("Stack is full");

this.st [++this.sp] = o;

}

 

public Object pop () throws StackException {

if (sp == -1)

throw new StackException ("Stack is empty");

Object o = this.st [this.sp];

this.sp–;

return o;

}

 

public boolean isEmpty() {

return this.sp == -1;

}

}

All right, now it’s time to write the Main class along with the main method. In this part, pay extra attention to the try-catch constructs. There are two kinds of exceptions to be caught (either the stack is empty or full). You’ll easily figure out their role.

public class Main {

public static void main (String args[]) {

Stack s = new Stack (10);

for (int i = 0; i <= 10; ++i)

try {

s.push (new Integer(i));

}

catch (StackException e) {

System.out.println (e);

}

while (! s.isEmpty() ) {

try {

System.out.println( (Integer)(s.pop()) );

}

catch (StackException e) {

System.out.println(e);

}

}

}

}

 

Of course, here’s the attached output as well. As you can see, the first line that is printed out is the exception, since we’re planning to fill the stack with 11 elements (consider: the for loop begins from 0 and goes up to 10 but also includes that value, this is a total of 11 elements), thus, the exception is thrown. Then it is also dealt with. The other exception doesn’t get thrown, since the while loop goes until isEmpty is false.

 

Stack is full

9

8

7

6

5

4

3

2

1

0

 

Play around with the above code for a little while. Try to pop another element. And don’t get surprised if the exception is thrown but also dealt with right away. That is the real power of exception handling, as you can see. So that’s it for now.

{mospagebreak title=Final Thoughts} 

Slowly but surely we’ve arrived at the end of this article. This means by now you’ve learned about exception handling. During this article I tried to focus mostly on practicality and explain those concepts that are especially important, while trying to prove why they cannot be neglected. Exceptions must be handled, period.

We all know that whether checked or unchecked, programmers ought to deal with exceptions, otherwise abnormal program termination may occur, and this problem must be minimized. No one can rely on, for example, the user never typing in the wrong data. The user can be pretty dumb… jokes aside, you get the idea!

As always, we stress the fact that theory without practice is barely worth anything. Ultimately, it’s up to you to deepen the knowledge presented here. And to be honest, what I covered in this article is barely the tip of the iceberg, though, the basics are spilled out. There are entire books written on the subject as well as very well-thought-out and prestigious documentation on exception handling. Check them out. 

In closing, I’d like to invite you to join our experienced community of technology professionals on all areas of IT&C starting from software and hardware up to consumer electronics at Dev Hardware Forums. As well, be sure to check out the community of our sister site at Dev Shed Forums. We are friendly and we’ll do our best to help you.

[gp-comments width="770" linklove="off" ]

chat