Throwing and Catching Exceptions

From Wikibooks, open books for an open world
Jump to: navigation, search

Exceptions Java Programming
Throwing and Catching Exceptions
Checked Exceptions
Navigate Exceptions topic:v  d  e )


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.

Computer code Code listing 6.1: SimpleDivisionOperation.java
  1. public class SimpleDivisionOperation {
    
  2.   public static void main(String[] args) {
    
  3.     System.out.println(divide(4, 2));
    
  4.     if (args.length > 1) {
    
  5.       int arg0 = Integer.parseInt(args[0]);
    
  6.       int arg1 = Integer.parseInt(args[1]);
    
  7.       System.out.println(divide(arg0, arg1));
    
  8.     }
    
  9.   }
    
  10.  
    
  11.   public static int divide(int a, int b) {
    
  12.     return a / b;
    
  13.   }
    
  14. }
    
Standard input or output Output for Code listing 6.1
$ java SimpleDivisionOperation 1 0
2
Exception in thread "main" java.lang.ArithmeticException: / by zero
     at SimpleDivisionOperation.divide(SimpleDivisionOperation.java:12)
     at SimpleDivisionOperation.main(SimpleDivisionOperation.java:7)

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]

The preceding exception could have been created explicitly by the developer as it is the case in the following code:

Computer code Code listing 6.2: SimpleDivisionOperation.java
  1. public class SimpleDivisionOperation {
    
  2.   public static void main(String[] args) {
    
  3.     System.out.println(divide(4, 2));
    
  4.     if (args.length > 1) {
    
  5.       // Convert a string to an integer
    
  6.       int arg0 = Integer.parseInt(args[0]);
    
  7.       int arg1 = Integer.parseInt(args[1]);
    
  8.       System.out.println(divide(arg0, arg1));
    
  9.     }
    
  10.   }
    
  11.  
    
  12.   public static int divide(int a, int b) {
    
  13.     if (b == 0) {
    
  14.       throw new ArithmeticException("You can\'t divide by zero!");       
    
  15.     } else {
    
  16.       return a / b;
    
  17.     }
    
  18.   }
    
  19. }
    
Standard input or output Output for Code listing 6.2
$ java SimpleDivisionOperation 1 0
2
Exception in thread "main" java.lang.ArithmeticException: You can't divide by zero!
at SimpleDivisionOperation.divide(SimpleDivisionOperation.java:14)
at SimpleDivisionOperation.main(SimpleDivisionOperation.java:7)

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. A exception object must inherit from java.lang.Exception. Standard exceptions have two constructors:

  1. The default constructor; and,
  2. A constructor taking a string argument so that you can place pertinent information in the exception.
Example Code section 6.1: Instance of an exception object with the default constructor.
  1. new Exception();
    
Example Code section 6.2: Instance of an Exception object by passing string in constructor.
  1. 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]

The box 6.1 below talks about the various exception classes within the java.lang package.

Box 6.1: The Java exception classes

Throwable 
The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement.
A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility was added in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another.
Error 
An Error indicates serious problems that a reasonable application should not try to handle. Most such errors are abnormal conditions.
Exception 
The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to handle. Also this is the class that a programmer may want to extend when adding business logic exceptions.
RuntimeException 
RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine. A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of the method but not caught.
Figure 6.2: The exception classes and their inheritance model in the JCL.
Java exception classes.svg

try/catch statement[edit]

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:

Example Code section 6.3: Division into a try block.
  1. int a = 4;
    
  2. int b = 2;
    
  3. int result = 0;
    
  4. try {
    
  5.   int c = a / b;
    
  6.   result = c;
    
  7. } catch(ArithmeticException ex) {
    
  8.   result = 0;
    
  9. }
    
  10. 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.

Example Code section 6.4: Catching 'division by zero' errors.
  1. int a = 4;
    
  2. int b = 0;
    
  3. int result = 0;
    
  4. try {
    
  5.   int c = a / b;
    
  6.   result = c;
    
  7. } catch(ArithmeticException ex) {
    
  8.   result = 0;
    
  9. }
    
  10. 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:

Example Code section 6.5: Uncaught exception.
  1. int a = 4;
    
  2. int b = 0;
    
  3. int result = 0;
    
  4. try {
    
  5.   int c = a / b;
    
  6.   result = c;
    
  7. } catch(NullPointerException ex) {
    
  8.   result = 0;
    
  9. }
    
  10. return result;
    

It is as if there is no try/catch statement. The exception is thrown to the calling method.

catch blocks[edit]

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.

Example Code section 6.6: Exception handling with catch blocks.
  1. try {
    
  2.   // Suppose the code here throws any exceptions,
    
  3.   // then each is handled in a separate catch block.
    
  4.  
    
  5.   int[] tooSmallArray = new int[2];
    
  6.   int outOfBoundsIndex = 10000;
    
  7.   tooSmallArray[outOfBoundsIndex] = 1;
    
  8.  
    
  9.   System.out.println("No exception thrown.");
    
  10. } catch(NullPointerException ex) {
    
  11.   System.out.println("Exception handling code for the NullPointerException.");
    
  12. } catch(NumberFormatException ex) {
    
  13.   System.out.println("Exception handling code for the NumberFormatException.");
    
  14. } catch(ArithmeticException | IndexOutOfBoundsException ex) {
    
  15.   System.out.println("Exception handling code for ArithmeticException"
    
  16.     + " or IndexOutOfBoundsException.");
    
  17. } catch(Exception ex) {
    
  18.   System.out.println("Exception handling code for any other Exception.");
    
  19. }
    
Standard input or output Output for Code section 6.6
Exception handling code for ArithmeticException or IndexOutOfBoundsException.

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]

A finally block can be added after the catch blocks. A finally block is always executed, even no exception is thrown, an exception is thrown and caught or an exception is thrown and not caught. It's a place to put a 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]

Let's examine the following code:

Warning Code section 6.7: Handling exceptions.
  1. public void methodA() throws SomeException {
    
  2.     // Method body
    
  3. }
    
  4.  
    
  5. public void methodB() throws CustomException, AnotherException {
    
  6.     // Method body
    
  7. }
    
  8.  
    
  9. public void methodC() {
    
  10.     methodB();
    
  11.     methodA();
    
  12. }
    

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:

Example Code section 6.8: Catching and throwing exceptions.
  1. public void methodC() throws CustomException, SomeException {
    
  2.   try {
    
  3.     methodB();
    
  4.   } catch(AnotherException e) {
    
  5.     // Handle caught exceptions.
    
  6.   }
    
  7.   methodA();
    
  8. }
    

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]


Clipboard

To do:
Add some exercises like the ones in Variables

Exceptions Java Programming
Throwing and Catching Exceptions
Checked Exceptions