Posted on Leave a comment

Rethrowing Exceptions – Exception Handling

Rethrowing Exceptions

Rethrowing an exception refers to throwing an exception in the body of a catch clause. The catch clause catches an exception, but then throws this exception or another exception in its body. This allows an exception to be partially handled when it is caught the first time, and then again when the rethrown exception is caught later. Typically, the first exception handler is a common handler for the situation and the later exception handler is a more specific one.

Exception parameters that are explicitly, implicitly, or effectively final in catch clauses allow the compiler to perform improved analysis of exception handling in the code, especially when it comes to rethrowing exceptions.

For the examples in this section, it is important to keep in mind that the exception type IOException is the supertype of both EOFException and FileNotFoundException.

Example 7.11 illustrates how the compiler is able to identify unreachable code by precise analysis of rethrown exceptions that are either final or effectively final. The body of the try statement at (1) can only throw a FileNotFoundException that is caught by the catch clause at (3). This exception is effectively final in the catch clause at (3), as no assignment is made to it in the body of the catch clause. This exception is rethrown in the nested try statement at (4), but the catch clause at (6) of this try statement can only catch an EOFException. Since parameter ex is effectively final, it can only denote a FileNotFoundException, never an EOFException. The catch clause at (6) is unreachable, and the compiler flags an error.

Example 7.11 Precise Rethrowing of Exceptions

Click here to view code image

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionAnalysis {
  public static void main(String[] args) throws IOException {
    try {                                // (1)
      throw new FileNotFoundException(); // (2)
    } catch (IOException ex) {           // (3)
      try {                        // (4) Nested try statement
        throw ex;                  // (5) Can only rethrow FileNotFoundException
      } catch (EOFException se) {  // (6) Compile-time error: clause unreachable
        System.out.println(“I am unreachable.”);
      }
}
  }
}

Example 7.12 illustrates how final or effectively final catch parameters allow more precise exceptions to be specified in the throws clause of a method. The thing to note is that the parameter e in the catch clause at (5) is not effectively final, as an assignment is made to the parameter at (6). All bets are off when the parameter is not final and the exception is rethrown. The throws clause must specify the same type as the type of the catch parameter, as shown at (3a). This has consequences for the caller method main(). Its try statement at (1) must include the catch clause at (2) to catch an IOException as well, or the compiler will flag an error about an uncaught checked exception. The contract of the checkIt() method allows for all exceptions that are either IOException or its subtypes.

If the assignment statement at (6) is commented out, the catch parameter e is effectively final in the catch body. The compiler can deduce that the rethrown exception can only be of type FileNotFoundException or EOFException. The throws clause of the checkIt() method can be made more specific, as at (3b). Note that the type of the catch parameter is the supertype IOException of the subtypes specified in the throws clause at (3b). Commenting out the assignment statement at (6) and uncommenting the more precise throws clause at (3b) has consequences for the caller method main() as well. The catch clause at (2) becomes unreachable, and the compiler issues a warning. Note also that the type of the exception parameter e at (5) is IOException, which is the supertype of the exception types specified in the throws clause. However, static analysis by the compiler is able to confirm that the exception parameter e can only denote objects of either FileNotFoundException or EOFException, but not of supertype IOException.

Example 7.12 Precise throws Clause

Click here to view code image

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
public class MorePreciseRethrow {
  public static void main(String[] args) {                        // (1)
    try {
      checkIt(1);
    } catch (FileNotFoundException fnfe) {
      System.out.println(“Check that the file exits.”);
    } catch (EOFException eofe) {
      System.out.println(“Check the contents of the file.”);
    } catch (IOException ioe) { // (2) mandatory with (3a), but compiler warning
                                //     that clause is unreachable with (3b).
      System.out.println(“This should never occur.”);
    }
  }
public static void checkIt(int value) throws IOException {      // (3a)
//public static void checkIt(int value)                           // (3b)
//    throws FileNotFoundException, EOFException {
    try {                                                         // (4)
      switch (value) {
        case 1:
          throw new FileNotFoundException(“File not found”);
        case 2:
          throw new EOFException(“End of file”);
        default:
          System.out.println(“OK”);
      }
    } catch (IOException e) {                                      // (5)
      System.out.println(e.getMessage());
      e = new EOFException(“End of file”);         // (6) not effectively final,
                                                   //     requires (3a).
                                                   //     When commented out,
                                                   //     can use (3b).
      throw e;
    }
  }
}

Program output with (3a) and (6) uncommented, and (3b) commented out:

Click here to view code image

File not found
Check the contents of the file.

Program output with (3a) and (6) commented out, and (3b) is uncommented:

Click here to view code image

File not found
Check that the file exits.

In summary, a throw statement in the body of a catch clause can throw a final or an effectively final exception parameter that has exception type E if all of the following conditions are satisfied:

  • Exception type E can be thrown in the body of the try statement with which the catch clause is associated.
  • Exception type E is assignment compatible with any of the exception types declared for the parameter in the catch clause.
  • Exception type E is not assignment compatible with any of the exception types declared for the parameters in any preceding catch clause in the same try statement.

In Example 7.13, the throw statements at (1), (2), and (3) all try to rethrow an exception that is effectively final in the body of the catch clause.

  • The throw statement at (1) in the main() method satisfies all the conditions. The try block throws an exception of the right type (EOFException). The exception thrown (EOFException) is assignment compatible with the type declared for the parameter in the catch clause (IOException). There is no preceding catch clause that handles the exception (EOFException).
  • The throw statement at (2) in the rethrowA() method cannot throw the exception, as the first condition is not satisfied: The try block does not throw an exception of the right type (EOFException). The compiler flags an error for the catch clause that is unreachable.
  • The throw statement at (3) in the rethrowB() method cannot throw the exception, as the third condition is not satisfied: A preceding catch clause can handle the exception (EOFException). The compiler flags a warning for the catch clause which is unreachable.

Example 7.13 Conditions for Rethrowing Final Exceptions

Click here to view code image

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
public class RethrowMe {
  public static void main(String[] args) throws EOFException {
    try {
      switch (1) {
        case 1: throw new FileNotFoundException(“File not found”);
        case 2: throw new EOFException(“End of file”);
        default: System.out.println(“OK”);
      }
    } catch (FileNotFoundException fnfe) {
      System.out.println(fnfe);
    } catch (IOException ioe) {
      throw ioe;                                                    // (1)
    }
  }
  public static void rethrowA() throws EOFException {
    try {
      // Empty try block.
    } catch (EOFException eofe) { // Compile-time error: exception not thrown
                                  //                     in try block.
      throw eofe;                                                   // (2)
    }
  }
  public static void rethrowB() throws EOFException {
    try {
      throw new EOFException(“End of file”);
    } catch (EOFException eofe) {
      System.out.println(eofe);
    } catch (IOException ioe) {   // Compile-time warning: unreachable clause
      throw ioe;                                                    // (3)
    }
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *