Pages

Exception Handling in Java

A Java exception is an object that describes an exceptional condition that has occurred in a piece of code. 
Categories of exceptions:
Checked exceptions: A checked exception is an exception that is typically a user error or a problem that cannot be foreseen by the programmer. For example, if a file is to be opened, but the file cannot be found, an exception occurs. These exceptions cannot simply be ignored at the time of compilation.
Runtime exceptions: A runtime exception is an exception that occurs that probably could have been avoided by the programmer. As opposed to checked exceptions, runtime exceptions are ignored at the time of compliation.
Errors: These are not exceptions at all, but problems that arise beyond the control of the user or the programmer. Errors are typically ignored in your code because you can rarely do anything about an error. For example, if a stack overflow occurs, an error will arise. They are also ignored at the time of compilation.
          When an exceptional condition arises, an object representing that exception is created and thrown in the method that caused the error. That method may choose to handle the exception itself, or pass it on. Either way, at some point, the exception is caught and processed. Exceptions can be generated by the Java run-time system, or they can be manually generated by your code. Exceptions thrown by Java relate to fundamental errors that violate the rules of the Java language or the constraints of the Java execution environment. Manually generated exceptions are typically used to report some error condition to the caller of a method. Java exception handling is managed via five keywords: try, catch, throw, throws, and finally
               Briefly, here is how they work. Program statements that you want to monitor for exceptions are contained within a try block. If an exception occurs within the try block, it is thrown. Your code can catch this exception (using catch) and handle it in some rational manner. System-generated exceptions are automatically thrown by the Java run-time system.
                To manually throw an exception, use the keyword throw. Any exception that is thrown out of a method must be specified as such by a throws clause. Any code that absolutely must be executed after a try block completes is put in a finally block.
This is the general form of an exception-handling block:
try
 {
// block of code to monitor for errors
}
catch (ExceptionType1 exObj)
{
// exception handler for ExceptionType1
}
catch (ExceptionType2 exObj)
{
// exception handler for ExceptionType2
}
// ...
finally
{
// block of code to be executed after try block ends
}

Here, ExceptionType is the type of exception that has occurred
Exception Types:
            All exception types are subclasses of the built-in class Throwable. Thus, Throwable is at the top of the exception class hierarchy. Immediately below Throwable are two subclasses that partition exceptions into two distinct branches. One branch is headed by Exception. This class is used for exceptional conditions that user programs should catch. This is also the class that you will subclass to create your own custom exception types. There is an important subclass of Exception, called RuntimeException. Exceptions of this type are automatically defined for the programs that you write and include things such as division by zero and invalid array indexing.
                    The other branch is topped by Error, which defines exceptions that are not expected to be caught under normal circumstances by your program. Exceptions of type Error are used by the Java run-time system to indicate errors having to do with the run-time environment, itself. Stack overflow is an example of such an error. This chapter will not be dealing with exceptions of type Error, because these are typically created in response to catastrophic failures that cannot usually be handled by your program.
try/catch Statement
        The try/catch statement encloses some code and is used to handle errors and exceptions that might occur in that code. Here is the general syntax of the try/catch statement:
try
{
    body-code
}
catch (exception-classname variable-name)
 {
    handler-code
}

              The try/catch statement has four parts. The body-code contains code that might throw the exception that we want to handle. The exception-classname is the class name of the exception we want to handle. The variable-name specifies a name for a variable that will hold the exception object if the exception occurs. Finally, the handler-code contains the code to execute if the exception occurs. After the handler-code executes, execution of the thread continues after the try/catch statement. Here is an example of code that tries to create a file in a non-existent directory which results in an IOException.
String filename = "/nosuchdir/myfilename";
try
 {
    // Create the file
    new File(filename).createNewFile();
}
catch (IOException e)
 {
    // Print out the exception that occurred
    System.out.println("Unable to create "+filename+": "+e.getMessage());
}
// Execution continues here after the IOException handler is executed

Here's the output:
Unable to create /nosuchdir/myfilename: The system cannot find the path specified.
                                  Although the default exception handler provided by the Java run-time system is useful for debugging, you will usually want to handle an exception yourself. Doing so provides two benefits. First, it allows you to fix the error. Second, it prevents the program from automatically terminating. Most users would be confused (to say the least) if your program stopped running and printed a stack trace whenever an error occurred! It is quite easy to prevent this.
                  To guard against and handle a run-time error, simply enclose the code that you want to monitor inside a try block. Immediately following the try block, include a catch clause that specifies the exception type that you wish to catch.
                 To illustrate how easily this can be done, the following program includes a try block and a catch clause that processes the ArithmeticException generated by the division-by-zero error:
class Exc2
 {
public static void main(String args[])
{
int d, a;
try
 { // monitor a block of code.
d = 0;
a = 42 / d;
System.out.println("This will not be printed.");
}
catch (ArithmeticException e)
 { // catch divide-by-zero error
System.out.println("Division by zero.");
}
System.out.println("After catch statement.");
}
}

This program generates the following output:
Division by zero.
After catch statement.
         Notice that the call to println( ) inside the try block is never executed. Once an exception is thrown, program control transfers out of the try block into the catch block. Put differently, catch is not “called,” so execution never “returns” to the try block from a catch. Thus, the line “This will not be printed.” is not displayed. Once the catch statement has executed, program control continues with the next line in the program following the entire try/catch mechanism.
         A try and its catch statement form a unit. The scope of the catch clause is restricted to those statements specified by the immediately preceding try statement. A catch statement cannot catch an exception thrown by another try statement (except in the case of nested try statements, described shortly). The statements that are protected by try must be surrounded by curly braces. (That is, they must be within a block.) You cannot use try on a single statement.
          The goal of most well-constructed catch clauses should be to resolve the exceptional condition and then continue on as if the error had never happened. For example, in the next program each iteration of the for loop obtains two random integers. Those two integers are divided by each other, and the result is used to divide the value 12345. The final result is put into a. If either division operation causes a divide-by-zero error, it is caught, the value of a is set to zero, and the program continues.
// Handle an exception and move on.
import java.util.Random;
class HandleError
{
public static void main(String args[])
 {
int a=0, b=0, c=0;
Random r = new Random();
for(int i=0; i<32000; i++)
 {
try
 {
b = r.nextInt();
c = r.nextInt();
a = 12345 / (b/c);
}
catch (ArithmeticException e)
 {
System.out.println("Division by zero.");
a = 0; // set a to zero and continue
}
System.out.println("a: " + a);
}
}
}



Multiple catch Clauses
In some cases, more than one exception could be raised by a single piece of code. To handle this type of situation, you can specify two or more catch clauses, each catching a different type of exception. When an exception is thrown, each catch statement is inspected in order, and the first one whose type matches that of the exception is executed. After one catch statement executes, the others are bypassed, and execution continues after the try/catch block. The following example traps two different exception types:
// Demonstrate multiple catch statements.
class MultiCatch
{
public static void main(String args[])
 {
Try
 {
int a = args.length;
System.out.println("a = " + a);
int b = 42 / a;
int c[] = { 1 };
c[42] = 99;
}
catch(ArithmeticException e)
{
System.out.println("Divide by 0: " + e);
}
catch(ArrayIndexOutOfBoundsException e)
 {
System.out.println("Array index oob: " + e);
}
System.out.println("After try/catch blocks.");
}
}
This program will cause a division-by-zero exception if it is started with no commandline arguments, since a will equal zero. It will survive the division if you provide a command-line argument, setting a to something larger than zero.
           But it will cause an ArrayIndexOutOfBoundsException, since the int array c has a length of 1, yet the program attempts to assign a value to c[42].
Here is the output generated by running it both ways:
C:\>java MultiCatch
a = 0
Divide by 0: java.lang.ArithmeticException: / by zero
After try/catch blocks.
C:\>java MultiCatch TestArg
a = 1
Array index oob: java.lang.ArrayIndexOutOfBoundsException:42
After try/catch blocks.
When you use multiple catch statements, it is important to remember that exception subclasses must come before any of their superclasses. This is because a catch statement that uses a superclass will catch exceptions of that type plus any of its subclasses. Thus, a subclass would never be reached if it came after its superclass. Further, in Java, unreachable code is an error.

No comments:

Post a Comment