Wednesday, February 9, 2011

Chapter 29: Exception Handling

Exception Handling is probably the most useful of the topics that are covered under the SCJP exam. Exception handling helps us catch or identify abnormal scenarios in our code and handle them appropriately instead of throwing up a random error on the front-end (User Interface) of the application.

Exception handling allows developers to detect errors easily without writing special code to test return values. Even better, it lets us keep exception-handling code cleanly separated from the exception-generating code. It also lets us use the same exception-handling code to deal with a range of possible exceptions.

Catching Exceptions - Using try and catch

The term “exception” means “exceptional condition” and is an occurrence that alters the normal program flow. A bunch of things can lead to exceptions, including hardware failures, resource exhaustion, and good old bugs. When an exceptional event occurs in Java, an exception is said to be “thrown.” The code that’s responsible for doing something about the exception is called an “exception handler,” and it “catches and handles” the thrown exception.

Exception handling works by transferring the execution of a program to an appropriate exception handler when an exception occurs. For ex: Your website displays the users bank account details. Suddenly if the bank database is down, imaging how the user would feel if an abrupt error page with numerous lines of java exception messages spewed all over the screen? First of all, it would be embarrassing and second of all, the user will get annoyed. Instead, if your code catches this database down scenario and displays a graceful message on screen saying “We are currently experiencing some difficulties in our system. Kindly try after some time. Thank you” it would be much better isnt it? That is exactly why we have or rather why we need Exception Handling.

To do this, we use the try and catch keywords. The try is used to define a block of code in which exceptions may occur. This block of code is called a guarded region (which really means “risky code goes here”). One or more catch clauses match a specific exception to a block of code that handles it. Here’s how it looks in pseudocode:

1. try {
2. // This is the "guarded region"
3. // All your bank database access code goes here
4. // And any other code that might process that data
5. // We may have many code lines here
6. }
7. catch(DatabaseDownException) {
8. // Put code here that handles this exception.
9. // Put the graceful error message here
10. // This is the last line of the exception handler.
11. }
12. catch(SomeOtherException) {
13. // Put code here that handles this exception
14. }
15.
16. // Some other unguarded code continues from here

In this pseudocode example, lines 2 through 5 constitute the guarded region that is governed by the try clause. Line 7 is an exception handler for an exception of type DatabaseDownException. Line 12 is an exception handler for an exception of type SomeOtherException. Notice that the catch blocks immediately follow the try block. This is a requirement; if you have one or more catch blocks, they must immediately follow the try block. Additionally, the catch blocks must all follow each other, without any other statements or blocks in between. Also, the order in which the catch blocks appear matters. For now just know this. We will see more in detail about their order a little bit later.

Execution of the guarded region starts at line 2. If the program executes all the way past line 5 with no exceptions being thrown, execution will transfer to line 15 and continue downward. However, if at any time in lines 2 through 5 (the try block) an exception is thrown of type DatabaseDownException, execution will immediately transfer to line 7. Lines 8 through 10 will then be executed so that the entire catch block runs, and then execution will transfer to line 15 and continue.
Note that if an exception occurred on, say, line 3 of the try block, the rest of the lines in the try block (4 and 5) would never be executed. Once control jumps to the catch block, it never returns to complete the balance of the try block. This is exactly what you want, though. Imagine your code looks something like this pseudocode:

try {
getTheFileFromOverNetwork
readFromTheFileAndPopulateTable
}
catch(CantGetFileFromNetwork) {
displayNetworkErrorMessage
}

The preceding pseudocode demonstrates how you typically work with exceptions. Code that’s dependent on a risky operation (as populating a table with file data is dependent on getting the file from the network) is grouped into a try block in such a way that if, say, the first operation fails, you won’t continue trying to run other code that’s also guaranteed to fail. In the pseudocode example, you won’t be able to read from the file if you can’t get the file off the network in the first place.

One of the benefits of using exception handling is that code to handle any particular exception that may occur in the governed region needs to be written only once. Returning to our earlier code example, there may be three different places in our try block that can generate a DatabaseDownException, but wherever it occurs it will be handled by the same catch block (on line 7).

Using finally

Although try and catch provide a great way to trap and handle exceptions, we are left with the problem of how to clean up if an exception occurs. Because execution transfers out of the try block as soon as an exception is thrown, we can’t put our cleanup code at the bottom of the try block and expect it to be executed if an exception occurs.

Exception handlers are a poor place to clean up after the code in the try block because each handler then requires its own copy of the cleanup code. If, for example, you opened a database connection somewhere in the guarded region, each exception handler would have to release the connection. That would make it too easy to forget to do cleanup, and also lead to a lot of redundant code. If you forget to close the connection in cases where an exception occurs, you will be left with orphan connections which can eventually crash your database. To address this problem, Java offers the finally block.

A finally block encloses code that is always executed at some point after the try block, whether an exception was thrown or not. Even if there is a return statement in the try block, the finally block executes right after the return statement is encountered, and before the return executes!

This is the right place to close your files, release your db connections, and perform any other cleanup your code requires. If the try block executes with no exceptions, the finally block is executed immediately after the try block completes. If there was an exception thrown, the finally block executes immediately after the proper catch block completes. Let’s look at another pseudocode example:

1: try {
2: // This is the first line of the "guarded region".
3: }
4: catch(DatabaseDownException) {
5: // Put code here that handles this exception
6: }
7: catch(SomeOtherException) {
8: // Put code here that handles this exception
9: }
10: finally {
11: // Put code here to release any resource we
12: // allocated in the try clause.
13: }
14:
15: // More code here

As before, execution starts at the first line of the try block, line 2. If there are no exceptions thrown in the try block, execution transfers to line 11, the first line of the finally block. On the other hand, if a SomeOtherException is thrown while the code in the try block is executing, execution transfers to the first line of that exception handler, line 8 in the catch clause. After all the code in the catch clause is executed, the program moves to line 11, the first line of the finally clause. To summarize – THE FINALLY BLOCK WILL EXECUTE ALWAYS. There is actually a catch here about the finally block executing always, but I will leave you to ponder over it for sometime. We will look at it a little later.

Actually, finally blocks are not required. If you don’t write one, your code will compile and run just fine. In fact, if you have no resources to clean up after your try block completes, you probably don’t need a finally clause. Also, because the compiler doesn’t even require catch clauses, sometimes you’ll run across code that has a try block immediately followed by a finally block. Such code is useful when the exception is going to be passed back to the calling method. But, using a finally block allows the cleanup code to execute even when there isn’t a catch clause.

The following legal code demonstrates a try with a finally but no catch:
try {
// do stuff
} finally {
//clean up
}

The following legal code demonstrates a try, catch, and finally:
try {
// do stuff
} catch (SomeException ex) {
// do exception handling
} finally {
// clean up
}

The following ILLEGAL code demonstrates a try without a catch or finally:
try {
// do stuff
}
// need a catch or finally here
System.out.println("out of try block");

The following ILLEGAL code demonstrates a misplaced catch block:
try {
// do stuff
}
// can't have code between try/catch
System.out.println("out of try block");
catch(Exception ex) { }

Exam Tip:

It is illegal to use a try clause without either a catch clause or a finally clause. A try clause by itself will result in a compiler error. Any catch clauses must immediately follow the try block. Any finally clause must immediately follow the last catch clause (or it must immediately follow the try block if there is no catch). It is legal to omit either the catch clause or the finally clause, but not both.
You can’t sneak any code in between the try, catch, or finally blocks. The following won’t compile:
try {
// do stuff
}
System.out.print("below the try"); //Illegal!
catch(Exception ex) { }

Propagating Uncaught Exceptions

Do we need to catch all possible exceptions a piece of code will generate? At all times? Actually, there’s no requirement that you code a catch clause for every possible exception that could be thrown from the corresponding try block. In fact, it’s doubtful that you could accomplish such a feat! If a method doesn’t provide a catch clause for a particular exception, that method is said to be “Propagating” the exception (or “passing the buck”).

So what happens to a propagated exception? Imagine a building, say, five stories high, and at each floor there is a deck or balcony. Now imagine that on each deck, one person is standing holding a bag. Exceptions are like balls dropped from person to person, starting from the roof. An exception is first thrown from the top of the stack (in other words, the person on the roof), and if it isn’t caught by the same person who threw it (the person on the roof), it drops down the call stack to the previous method, which is the person standing on the deck one floor down. If not caught there, by the person one floor down, the exception/ball again drops down to the previous method (person on the next floor down), and so on until it is caught or until it reaches the very bottom of the call stack. This is called exception propagation.

If an exception reaches the bottom of the call stack, it’s like reaching the bottom of a very long drop; the ball explodes, and so does your program. An exception that’s never caught will cause your application to stop running. A description (if one is available) of the exception will be displayed, and the call stack will be “dumped.” This helps you debug your application by telling you what exception was thrown, from what method it was thrown, and what the stack looked like at the time. Unfortunately, this would be a miserable sight for the user using your system. So, the lesson here is – always have a person waiting in ground floor ready to catch the ball i.e., make sure you handle all exceptions in your classes somewhere in the method calling hierarchy.

Exam Tip:
You can keep throwing an exception down through the methods on the stack. But what about when you get to the main() method at the bottom? You can throw the exception out of main() as well. This results in the Java Virtual Machine (JVM) halting, and the stack trace will be printed to the output.
The following code throws an exception,
class TestExceptionPropagation {
public static void main (String [] args) {
doSomething();
}
static void doSomething() {
doMoreThings();
}
static void doMoreThings() {
int x = 5/0; // Can't divide by zero!
// ArithmeticException is thrown here
}
}

which prints out a stack trace something like,
%java TestExceptionPropagation
Exception in thread "main" java.lang.ArithmeticException: /
by zero
at TestExceptionPropagation.doMoreThings(TestExceptionPropagation.java:10)
at TestExceptionPropagation.doSomething(TestExceptionPropagation.java:7)
at TestExceptionPropagation.main(TestExceptionPropagation.java:3)

Defining Exceptions

We have been discussing exceptions as a concept. We know that they are thrown when a problem of some sort happens, and we know what effect they have on the flow of our program. In this section we will develop the concepts further and use exceptions in functional Java code. Earlier we said that an exception is an occurrence that alters the normal program flow. But because this is Java, anything that’s not a primitive must be an object. Exceptions are no exception to this rule. Every exception is an instance of a class that has class Exception in its inheritance hierarchy. In other words, exceptions are always some subclass of java.lang.Exception.

When an exception is thrown, an object of a particular Exception subtype is instantiated and handed to the exception handler as an argument to the catch clause. An actual catch clause looks like this:
try {
// some code here
}
catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
}

In this example, e is an instance of the ArrayIndexOutOfBoundsException class. As with any other object, you can call its methods.

Exception Hierarchy

All exception classes are subtypes of class Exception. This class derives from the class Throwable (which derives from the class Object). The Figure below shows the hierarchy for the exception classes.

Exception class hierarchy


As you can see, there are two subclasses that derive from Throwable: Exception and Error. Classes that derive from Error represent unusual situations that are not caused by program errors, and indicate things that would not normally happen during program execution, such as the JVM running out of memory. Generally, your application won’t be able to recover from an Error, so you’re not required to handle them. If your code does not handle them (and it usually shouldn’t and won’t), it will still compile with no trouble. Although often thought of as exceptional conditions, Errors are technically not exceptions because they do not derive from class Exception.

In general, an exception represents something that happens not as a result of a programming error, but rather because some resource is not available or some other condition required for correct execution is not present. For example, if your application is supposed to communicate with another application or computer that is not answering, this is an exception that is not caused by a bug.

Java provides many exception classes, most of which have quite descriptive names. There are two ways to get information about an exception. The first is from the type of the exception itself. The next is from information that you can get from the exception object. Class Throwable (at the top of the inheritance tree for exceptions) provides its descendants with some methods that are useful in exception handlers. One of these is printStackTrace(). As expected, if you call an exception object’s printStackTrace() method, as in the earlier example, a stack trace from where the exception occurred will be printed.

You will notice that the printStackTrace() method prints the most recently entered method first and continues down, printing the name of each method as it works its way down the call stack from the top.

Exam Tip:

For the Exam, you need to remember that Exception, Error, RuntimeException and Throwable types can all be thrown using the “throw” keyword and can all be caught using catch blocks.

Handling an Entire Class Hierarchy of Exceptions

We’ve discussed that the catch keyword allows you to specify a particular type of exception to catch. You can actually catch more than one type of exception in a single catch clause. If the exception class that you specify in the catch clause has no subclasses, then only the specified class of exception will be caught. However, if the class specified in the catch clause does have subclasses, any exception object that subclasses the specified class will be caught as well.
For example, class IndexOutOfBoundsException has two subclasses, ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. You may want to write one exception handler that deals with exceptions produced by either type of boundary error, but you might not be concerned with which exception you actually have. In this case, you could write a catch clause like the following:

try {
// Some code here that can throw a boundary exception
}
catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}

If any code in the try block throws ArrayIndexOutOfBoundsException or StringIndexOutOfBoundsException, the exception will be caught and handled. This can be convenient, but it should be used with caution. By specifying an exception class’s superclass in your catch clause, you’re discarding valuable information about the exception. You can, of course, find out exactly what exception class you have inside the catch block, but if you’re going to do that, you’re better off writing a separate catch clause for each exception type of interest.

Important Tip:
Always resist the temptation to write a single catch-all exception handler such as the following:
try {
// some code
}
catch (Exception e) {
e.printStackTrace();
}


This code will catch every exception generated. Of course, no single exception handler can properly handle every exception, and programming in this way defeats the design objective. Exception handlers that trap many errors at once will probably reduce the reliability of your program because it’s likely that an exception will be caught that the handler does not know how to handle.

Exception Matching
If you have an exception hierarchy composed of a superclass exception and a number of subtypes, and you’re interested in handling one of the subtypes in a special way but want to handle all the rest together, you need write only two catch clauses.
When an exception is thrown, Java will try to find (by looking at the available catch clauses from the top down) a catch clause for the exception type. If it doesn’t find one, it will search for a handler for a supertype of the exception. If it does not find a catch clause that matches a supertype for the exception, then the exception is propagated down the call stack. This process is called exception matching. Let’s look at an example:

1: import java.io.*;
2: public class ExceptionMatchingExample {
3: public static void main(String args[]) {
4: try {
5: RandomAccessFile raf =
6: new RandomAccessFile("myfile.txt", "r");
7: byte b[] = new byte[1000];
8: raf.readFully(b, 0, 1000);
9: }
10: catch(FileNotFoundException e) {
11: System.err.println("File not found");
12: System.err.println(e.getMessage());
13: e.printStackTrace();
14: }
15: catch(IOException e) {
16: System.err.println("IO Error");
17: System.err.println(e.toString());
18: e.printStackTrace();
19: }
20: }
21: }

This short program attempts to open a file and to read some data from it. Opening and reading files can generate many exceptions, most of which are some type of IOException. Imagine that in this program we’re interested in knowing only whether the exact exception is a FileNotFoundException. Otherwise, we don’t care exactly what the problem is.

FileNotFoundException is a subclass of IOException. Therefore, we could handle it in the catch clause that catches all subtypes of IOException, but then we would have to test the exception to determine whether it was a FileNotFoundException. Instead, we coded a special exception handler for the FileNotFoundException and a separate exception handler for all other IOException subtypes.

If this code generates a FileNotFoundException, it will be handled by the catch clause that begins at line 10. If it generates another IOException—perhaps EOFException, which is a subclass of IOException—it will be handled by the catch clause that begins at line 15. If some other exception is generated, such as a runtime exception of some type, neither catch clause will be executed and the exception will be propagated down the call stack.

Notice that the catch clause for the FileNotFoundException was placed above the handler for the IOException. This is really important! If we do it the opposite way, the program will not compile. The handlers for the most specific exceptions must always be placed above those for more general exceptions. The following will not compile:

try {

} catch (IOException e) {

} catch (FileNotFoundException ex) {

}

You’ll get a compiler error something like this:
TestExceptionPropagation.java:15: exception java.io.FileNotFoundException has
already been caught
} catch (FileNotFoundException ex) {
^

Exception Declaration

So, how do we know that some method throws an exception that we have to catch? Just as a method must specify what type and how many arguments it accepts and what is returned, the exceptions that a method can throw must be declared. The list of thrown exceptions is part of a method’s public interface. The throws keyword is used as follows to list the exceptions that a method can throw:

void myMethod() throws MyException1, MyException2 {
// code for the method here
}

This method has a void return type, accepts no arguments, and declares that it can throw one of two types of exceptions: either type MyException1 or type MyException2. (Just because the method declares that it throws an exception doesn’t mean it always will. It just tells the calling method that it might.)

Suppose your method doesn’t directly throw an exception, but calls a method that does. You can choose not to handle the exception yourself and instead just declare it, as though it were your method that actually throws the exception. If you do declare the exception that your method might get from another method, and you don’t provide a try/catch for it, then the method will propagate back to the method that called your method, and either be caught there or continue on to be handled by a method further down the stack.

Any method that might throw an exception (unless it’s a subclass of RuntimeException) must declare the exception. That includes methods that aren’t actually throwing it directly, but are “propagating” and letting the exception pass down to the next method in the stack. If you “propagate” an exception, it is just as if you were the one actually throwing the exception. RuntimeException subclasses are exempt, so the compiler won’t check to see if you’ve declared them. But all non-RuntimeExceptions are considered “checked” exceptions, because the compiler checks to be certain you’ve acknowledged that “bad things could happen here.”
Remember this: Each method must either handle all checked exceptions by supplying a catch clause or list each unhandled checked exception as a thrown exception.
This rule is referred to as Java’s “handle or declare” requirement. (Sometimes called “catch or declare.”)

Again, some exceptions are exempt from this rule. An object of type RuntimeException may be thrown from any method without being specified as part of the method’s public interface (and a handler need not be present). And even if a method does declare a RuntimeException, the calling method is under no obligation to handle or declare it. RuntimeException, Error, and all of their subtypes are unchecked exceptions and unchecked exceptions do not have to be specified or handled. Here is an example:

import java.io.*;
class Test {
public int myMethod1() throws EOFException {
return myMethod2();
}
public int myMethod2() throws EOFException {
// code that actually could throw the exception goes here
return 1;
}
}

Let’s look at myMethod1(). Because EOFException subclasses IOException and IOException subclasses Exception, it is a checked exception and must be declared as an exception that may be thrown by this method. But where will the exception actually come from? The public interface for method myMethod2() called here declares that an exception of this type can be thrown. Whether that method actually throws the exception itself or calls another method that throws it is unimportant to us; we simply know that we have to either catch the exception or declare that we throw it. The method myMethod1() does not catch the exception, so it declares that it throws it. Now let’s look at another legal example, myMethod3().

public void myMethod3() {
// code that could throw a NullPointerException goes here
}

According to the comment, this method can throw a NullPointerException. Because RuntimeException is the superclass of NullPointerException, it is an unchecked exception and need not be declared. We can see that myMethod3() does not declare any exceptions.

Runtime exceptions are referred to as unchecked exceptions. All other exceptions are checked exceptions, and they don’t derive from java.lang.RuntimeException. A checked exception must be caught somewhere in your code. If you invoke a method that throws a checked exception but you don’t catch the checked exception somewhere, your code will not compile. That’s why they’re called checked exceptions; the compiler checks to make sure that they’re handled or declared. A number of the methods in the Java 2 Standard Edition libraries throw checked exceptions, so you will often write exception handlers to cope with exceptions generated by methods you didn’t write.

You can also throw an exception yourself, and that exception can be either an existing exception from the Java API or one of your own. To create your own exception, you simply subclass Exception (or one of its subclasses) as follows:
class MyException extends Exception { }

And if you throw the exception, the compiler will guarantee that you declare it as follows:
class TestExceptionPropagation {
void doSomething() {
throw new MyException(); // Throw a checked exception
}
}

The preceding code upsets the compiler:
TestExceptionPropagation.java:6: unreported exception MyException; must be caught
or
declared to be thrown
throw new MyException();
^

You need to know how an Error compares with checked and unchecked exceptions. Objects of type Error are not Exception objects, although they do represent exceptional conditions. Both Exception and Error share a common superclass, Throwable, thus both can be thrown using the throw keyword. When an Error or a subclass of Error is thrown, it’s unchecked. You are not required to catch Error objects or Error subtypes. You can also throw an Error yourself and you can catch one, but again, you probably won’t. For example, what would you do if a VirtualMachineError arose? Your program is done or rather dead by the time you’d catch the Error, so there’s really no point in trying to catch one of these things. Just remember, though, that you can! The following code compiles just fine:

class TestExceptionPropagation {
public static void main (String [] args) {
badMethod();
}
static void badMethod() { // No need to declare an Error
doSomething();
}
static void doSomething() { //No need to declare an Error
try {
throw new Error();
}
catch(Error me) {
throw me; // We catch it, but then rethrow it
}
}
}

If we were throwing a checked exception rather than Error, then the doSomething() method would need to declare the exception. But remember, since Error is not a subtype of Exception, it doesn’t need to be declared. You’re free to declare it if you like, but the compiler just doesn’t care one way or another when or how the Error is thrown, or by whom.

Exam Tip:
When an object of a subtype of Exception is thrown, it must be handled or declared. These objects are called checked exceptions, and include all exceptions except those that are subtypes of RuntimeException, which are unchecked exceptions. Be ready to spot methods that don’t follow the “handle or declare” rule, such as
class MyException extends Exception {
void someMethod () {
doSomething();
}
void doSomething() throws MyException {
try {
throw new MyException();
}
catch(MyException me) {
throw me;
}
}
}

You need to recognize that this code won’t compile. If you try, you’ll get
MyException.java:3: unreported exception MyException; must
be caught or declared to be thrown
doSomething();
^
Notice that someMethod() fails to either handle or declare the exception that can be thrown by doSomething().

Rethrowing the Same Exception

Just as you can throw a new exception from a catch clause, you can also throw the same exception you just caught. Here’s a catch clause that does this:
catch(IOException e) {
// Do things, then if you decide you can't handle it...
throw e;
}

All other catch clauses associated with the same try are ignored, if a finally block exists, it runs, and the exception is thrown back to the calling method (the next method down the call stack). If you throw a checked exception from a catch clause, you must also declare that exception! In other words, you must handle and declare, as opposed to handle or declare. The following example is illegal:

public void doSomething() {
try {
// risky IO things
} catch(IOException ex) {
// can't handle it
throw ex; // Can't throw it unless you declare it
}
}

In the preceding code, the doSomething() method is clearly able to throw a checked exception—in this case an IOException—so the compiler says, “Well, you have a try/catch in there, but it’s not good enough. If you might rethrow the IOException you catch, then you must declare it!”

Previous Chapter: Chapter 28: Loops and Iterators

Next Chapter: Chapter 30 - Common Exceptions and Errors

No comments:

Post a Comment

© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers