Throwing and Catching Exceptions
Navigate Exceptions topic: ) |
Language compilers are adept at pointing out most of the erroneous code in a program, however there are some errors that only become apparent when the program is executed. Consider the code listing 6.1; here, the program defines a method divide that does a simple division operation taking two integers as parameter arguments and returning the result of their division. It can safely be assumed that when the divide(4, 2) statement is called, it would return the number 2. However, consider the next statement, where the program relies upon the provided command line arguments to generate a division operation. What if the user provides the number zero (0) as the second argument? We all know that division by zero is impossible, but the compiler couldn't possibly have anticipated the user providing zero as an argument.
|
|
Such exceptional code that results in erroneous interpretations at program runtime usually results in errors that are called exceptions in Java. When the Java interpreter encounters an exceptional code, it halts execution and displays information about the error that occurs. This information is known as a stack trace. The stack trace in the above example tells us more about the error, such as the thread — "main"
— where the exception occurred, the type of exception — java.lang.ArithmeticException
, a comprehensible display message — / by zero
, and the exact methods and the line numbers where the exception may have occurred.
Exception object
[edit | edit source]The preceding exception could have been created explicitly by the developer as it is the case in the following code:
|
|
Note that when b
equals zero, there is no return value. Instead of a java.lang.ArithmeticException
generated by the Java interpreter itself, it is an exception created by the coder. The result is the same. It shows you that an exception is an object. Its main particularity is that it can be thrown. An exception object must inherit from java.lang.Exception
. Standard exceptions have two constructors:
- The default constructor; and,
- A constructor taking a string argument so that you can place pertinent information in the exception.
Code section 6.1: Instance of an exception object with the default constructor.
new Exception();
|
Code section 6.2: Instance of an Exception object by passing string in constructor.
new Exception("Something unexpected happened");
|
This string can later be extracted using various methods, as you can see in the code listing 6.2.
You can throw any type of Throwable object using the keyword throw
. It interrupts the method. Anything after the throw statement would not be executed, unless the thrown exception is handled. The exception object is not returned from the method, it is thrown from the method. That means that the exception object is not the return value of the method and the calling method can be interrupted too and so on and so on...
Typically, you'll throw a different class of exception for each different type of error. The information about the error is represented both inside the exception object and implicitly in the name of the exception class, so someone in the bigger context can figure out what to do with your exception. Often, the only information is the type of exception, and nothing meaningful is stored within the exception object.
Oracle standard exception classes
[edit | edit source]The box 6.1 below talks about the various exception classes within the java.lang
package.
Box 6.1: The Java exception classes
|
Figure 6.2: The exception classes and their inheritance model in the JCL. |
try
/catch
statement
[edit | edit source]Try/Catch is straight up better.
By default, when an exception is thrown, the current method is interrupted, the calling method is interrupted too and so on till the main
method. A thrown exception can also be caught using a
try
/catch
statement. Below is how a try
/catch
statement works:
Code section 6.3: Division into a try block.
int a = 4;
int b = 2;
int result = 0;
try {
int c = a / b;
result = c;
} catch(ArithmeticException ex) {
result = 0;
}
return result;
|
The executed code lines have been highlighted. When no exception is thrown, the method flow executes the try
statement and not the catch
statement.
Code section 6.4: Catching 'division by zero' errors.
int a = 4;
int b = 0;
int result = 0;
try {
int c = a / b;
result = c;
} catch(ArithmeticException ex) {
result = 0;
}
return result;
|
As there is a thrown exception at line 5, the line 6 is not executed, but the exception is caught by the catch
statement so the catch
block is executed. The following code is also executed. Note that the catch
statement takes an exception as parameter. There is a third case: when the exception is not from the same class as the parameter:
Code section 6.5: Uncaught exception.
int a = 4;
int b = 0;
int result = 0;
try {
int c = a / b;
result = c;
} catch(NullPointerException ex) {
result = 0;
}
return result;
|
It is as if there is no try
/catch
statement. The exception is thrown to the calling method.
catch
blocks
[edit | edit source]A try
/catch
statement can contain several catch
blocks, to handle different exceptions in different ways. Each catch
block must take a parameter of a different throwable class. A thrown object may match several catch
block but only the first catch
block that matches the object will be executed. A catch-block will catch a thrown exception if and only if:
- the thrown exception object is the same as the exception object specified by the catch-block.
- the thrown exception object is the subtype of the exception object specified by the catch-block.
This means that the catch
block order is important. As a consequence, you can't put a catch
block that catches all the exception (which take a java.lang.Exception
as parameter) before a catch
block that catches a more specific exception as the second block could never be executed.
|
|
At line 14, we use a multi-catch clause. It is available since the JDK 7. This is a combination of several catch clauses and let's you handle exceptions in a single handler while also maintaining their types. So, instead of being boxed into a parent Exception super-class, they retain their individual types.
You can also use the java.lang.Throwable
class here, since Throwable is the parent class for the application-specific Exception classes. However, this is discouraged in Java programming circles. This is because Throwable happens to also be the parent class for the non-application specific Error classes which are not meant to be handled explicitly as they are catered for by the JVM itself.
finally
block
[edit | edit source]A finally
block can be added after the catch
blocks. A finally
block is always executed, even when no exception is thrown, an exception is thrown and caught, or an exception is thrown and not caught. It's a place to put code that should always be executed after an unsafe operation like a file close or a database disconnection. You can define a try
block without catch
block, however, in this case, it must be followed by a finally
block.
Example of handling exceptions
[edit | edit source]Let's examine the following code:
In the code section 6.7, methodC
is invalid. Because methodA
and methodB
pass (or throw) exceptions, methodC
must be prepared to handle them. This can be handled in two ways: a try
-catch
block, which will handle the exception within the method and a throws
clause which would in turn throw the exception to the caller to handle. The above example will cause a compilation error, as Java is very strict about exception handling. So the programmer is forced to handle any possible error condition at some point.
A method can do two things with an exception: ask the calling method to handle it by the throws
declaration or handle the exception inside the method by the try
-catch
block.
To work correctly, the original code can be modified in multiple ways. For example, the following:
Code section 6.8: Catching and throwing exceptions.
public void methodC() throws CustomException, SomeException {
try {
methodB();
} catch(AnotherException e) {
// Handle caught exceptions.
}
methodA();
}
|
The AnotherException
from methodB
will be handled locally, while CustomException
and SomeException
will be thrown to the caller to handle it. Most of the developers are embarrassed when they have to choose between the two options. This type of decision should not be taken at development time. If you are a development team, it should be discussed between all the developers in order to have a common exception handling policy.
Keyword references
[edit | edit source]