"Java Exception Handling -
Basics
*Note the examples are for explanation purposes
only, and may not be the most efficient way to complete the problems/tasks set
forward.
**These examples use the main method as to not over complicate the
information, but this is applicable to any and all methods within a
class.
Java will generate many exceptions during your time coding
with this language. Some will be wanted, some will not be wanted, but they all
must be dealt with to produce a good piece of programming code.
First of
all,this tutorial will not help you determine the difference between the
exceptions you know how to handle, and the ones you don't, but it will show you
how to order them and group them, once you have made such a distinction in your
program.
You have a few choices when you are confronted with an
exception.
1) There is actually an error in your code, which needs to be
fixed.
2) This is something which cannot be handled and needs to be dealt
with.
3) This is something which cannot be handled and needs to be
ignored.
numbers 2) and 3) are the more easy ones to deal with as it
means your code is essentially correct, it is just possible to do something
anyway which may generate an error.
*Side Note*
Many of these come
from interfaces:
1) When multiple interfaces are implemented on a single
object, or they inherit from each other. Sometimes the JVM has to make
decisions, where you meant no code to run, some code is running.
2) If there
are two or more types of objects and somehow an object of interface 1 is trying
to be an object of interface 2. This can occur in both bad coding and
intentional overlap, and handled by error checking.
*End Side
Note*
Dealing with
Existing Java Exceptions:
(Java.lang.Exception)
There
is a large list of subclasses which each have there own subclasses of
Exceptions, which Java is fully able to understand and give feedback on the
reason for the triggering of the exception.
A classic example, i'm sure
you have all run into is the java.lang.ArrayIndexOutOfBoundsException, when you try to access
an element passed the end of an array. This will be the first example of an
exception to which we will handle.
Generates an unwanted Exception:
view source
print
?
1
public class exceptions{
2
public static
void main(String
Args[]){
3
int[] array = new int[3];
4
for(int i=0;i<4;++i){
5
array[i] = i;
6
}
7
System.out.println(array);
8
}
9
}
so
now we have an unwanted exception, perhaps what we really wanted to do was build
a ciclic array, which points to first slot once we pass the end of the
array.
For this simple task, we will use a try
catch
block to trap the errors and send them to where we know how to
handle them.
Simple Solution - The Try Catch Block:
view source
print
?
01
public class exceptions{
02
public static
void main(String
Args[]){
03
int[] array = new int[3];
04
try{
05
for(int i=0;i<4;++i){
06
array[i] = i;
07
}
08
System.out.println(array);
09
}
10
catch(ArrayIndexOutOfBoundsException e){
11
//printed just to inform that we have entered the catch
block
12
System.out.println("Oops, we
went to far, better go back to 0!");
13
}
14
}
15
}
Now
that the error is handled, we simply get a nice message telling us what
happened, but the code has not stopped
it will
continue until it reaches the end or another Exception. This is where you may
modify variables that have exceeded their range, and other such problems created
under the Exception heading.
*Notice that our line System.out.println(array); gets skipped due to the
exception. It is okay to place this line inside of the catch block, as it will
not generate an exception of it's own (assuming array exists), but i will use
this to demonstrate the addition of the finally
block.
In addition to the Try
and catch
blocks there is also the option to add Finally
. This is a block of code which should be free of
exceptions in all circumstances as it will be run, no matter what!
If the try
block completes without an Exception, the finally block excecutes.
If there
is an Exception, once the catch block completes, the finally block
excecutes.
This is where you get the program back on course after a possible
exception, by calling your update methods and reset variables
that should be reset in all cases.
Simple Extension - Finally Block:
view source
print
?
01
public class exceptions{
02
public static
void main(String
Args[]){
03
int[] array = new int[3];
04
try{
05
for(int i=0;i<4;++i){
06
array[i] = i;
07
}
08
System.out.println(array);
09
}
10
catch(ArrayIndexOutOfBoundsException e){
11
//printed just to inform that we have entered the catch
block
12
System.out.println("Oops, we
went to far, better go back to 0!");
13
}
14
finally{
15
System.out.println(array);
16
//method call to continue program
17
}
18
}
19
}
I
realize that printing the array is not all that exciting, especially since it is
just an address in memory, but it shows how the code continutes. Try changing
the for loop to i<3 and see how the Exception
is not generated and that the array address is then printed twice! To correct
this, simply remove the println from the try block and only the finally block
will be printed each time.
Now that we can catch Exceptions, there are
many additions to be found in java which will give more insight into where the
Exception was generated.
All stack traces are from present
location back to the source of the Exception
*items which are rarely
used
fillInStackTrace:
-displays the
excecution cylce of the stack trace.
getCause
-returns the cause of the Exception, in most
cases this will be null
getLocalizedMessage
-a description of why the Exception
was thrown, usually not that informative without other information
getMessage
-the detailed description, usually exactly the
same as getLocalizedMessage, but not always in a large program
getStackTrace
-displays memory address of trace
points
*initCause
-saves the cause of the
exception to be passed or recreated
printStackTrace
-detailed list of all excecutions
including line numbers, printed without System.out
*setStackTrace
-allows for modification of the trace points
(beyond the scope of this tutorial)
toString
-string representation of the Exception, used
when throwing (throwing seen in next tutorial)
How to use the above
methods on an exception:
view source
print
?
01
import java.lang.*;
02
public class exceptions{
03
public static
void main(String
Args[]){
04
int[] array = new int[3];
05
try{
06
for(int i=0;i<4;++i){
07
array[i] = i;
08
}
09
System.out.println(array);
10
}
11
catch(ArrayIndexOutOfBoundsException e){
12
System.out.println("filIn:
" + e.fillInStackTrace());
13
System.out.println("cause:
" + e.getCause());
14
System.out.println("local:
" + e.getLocalizedMessage());
15
System.out.println("messa:
" + e.getMessage());
16
System.out.println("trace:
" + e.getStackTrace());
17
System.out.println();
18
System.out.println();
19
System.out.print("trace:
"); e.printStackTrace();
20
System.out.println();
21
System.out.print("string:
");e.toString();
22
System.out.println();
23
System.out.println();
24
//printed just to inform that we have entered the catch
block
25
System.out.println("Oops, we
went to far, better go back to 0!");
26
throw (Exception)
new Exception().initCause(e);
27
}
28
finally{
29
System.out.println(array);
30
//method call to continue program
31
}
32
}
33
}
Output:
Quote
filIn: java.lang.ArrayIndexOutOfBoundsException: 3
cause:
null
local: 3
messa: 3
trace:
[Ljava.lang.StackTraceElement;@194df86
trace:
java.lang.ArrayIndexOutOfBoundsException: 3
at
exceptions.main(exceptions.java:12)
string:
Oops, we went to far,
better go back to 0!
[I@defa1a
Exception in thread "main"
java.lang.Exception
at exceptions.main(exceptions.java:26)
Caused by:
java.lang.ArrayIndexOutOfBoundsException: 3
at
exceptions.main(exceptions.java:12)
Press any key to
continue...
*Notice that the exception is thrown at line 26,
where we recreated the initCause and still points to the
ArrayIndexOutOfBoundsException in the original cause.
Up to now we
have dealt with a single Exception. What if there are multiple exceptions, but
they all need to be handled differently?
Some things to keep in mind:
1)
The class Exception
will catch all Exceptions no
matter their source or cause.
2) Always handle Exceptions from the most
specific and towards less specific.
3) It is a good idea to always make the
last case in your catch block the Exception class to handle all unknown or
unpredicted Exceptions.
Keeping with the same basic example, but i have
removed all of the additional information and added a couple of new problems that need to be dealt with.
The Base Code:
view source
print
?
01
public class exceptions{
02
public static
void main(String
Args[]){
03
int[] array = new int[3];
04
for(int i=0;i<3;++i){
05
array[i] = i;
06
}
07
array[0] = 2/0;
08
System.out.println(array);
09
}
10
}
*We
have fixed the ArrayOutOfBoundsException, just in case let's leave that Catch
option in.
Now we will add to this code. Since dividing by zero is an
ArithmeticException, you can find this out by simply running the code
above.
The end result is:
view source
print
?
01
public class exceptions{
02
public static
void main(String
Args[]){
03
int[] array = new int[3];
04
try{
05
for(int i=0;i<3;++i){
06
array[i] = i;
07
}
08
array[0] = 2/0;
09
}
10
catch(ArrayIndexOutOfBoundsException e){
11
System.out.println("Oops, we
went to far, better go back to 0!");
12
}
13
catch(ArithmeticException
e){
14
System.out.println("Cannot
Divide by Zero!");
15
//method call to continue program
16
}
17
catch(Exception e){
18
System.out.println("An
Unknown Error has Occured");
19
e.printStackTrace();
20
}
21
finally{
22
System.out.println(array);
23
//method call to continue program
24
}
25
}
26
}
This
time the ArrayIndexOutOfBoundsException is skipped, since the error generated
was not of this type, but once it reached ArithmeticException, the category was
correct and the code was executed. Catch blocks can be written in this order as
many as are required.
To illustrate why the Exceptions are written in this
order, run the following code which reverses ArithmeticException and
Exception:
view source
print
?
01
public class exceptions{
02
public static
void main(String
Args[]){
03
int[] array = new int[3];
04
try{
05
for(int i=0;i<3;++i){
06
array[i] = i;
07
}
08
array[0] = 2/0;
09
}
10
catch(ArrayIndexOutOfBoundsException e){
11
System.out.println("Oops, we
went to far, better go back to 0!");
12
}
13
catch(Exception e){
14
System.out.println("An
Unknown Error has Occured");
15
e.printStackTrace();
16
}
17
catch(ArithmeticException
e){
18
System.out.println("Cannot
Divide by Zero!");
19
//method call to continue program
20
}
21
finally{
22
System.out.println(array);
23
//method call to continue program
24
}
25
}
26
}
*If
you have a good compiler, this should not compile at all!
Because
ArithmeticException is a subclass of Exception, thus it can also handle the
ArithmeticException, and becomes useless and will want to be thrown or caught,
which cannot be done with Exception catching everything that comes it's
way.
This also opens the door for grouping of errors, if you wish to
treat all errors the same then only use Exception, or seperate by large
subclasses. There is also the otherside where you could individualize each case,
and even add some of your own (which will be talked about in another tutorial."