Posted on Leave a comment

The Multi-catch Clause – Exception Handling

7.6 The Multi-catch Clause

Example 7.9 uses a try block that has multiple uni-catch clauses. This example is based on Example 7.8. The sum of the values and the number of values needed to calculate the average are now read as program arguments from the command line at (2) and (3), respectively. The example shows a try statement at (1) that uses three uni-catch clauses: at (5), (6), and (7). In a uni-catch clause, a single exception type is specified for the catch parameter.

In Example 7.9, the method printAverage() is only called at (4) if there are at least two consecutive integers specified on the command line. An unchecked ArrayIndexOutOfBoundsException is thrown if there are not enough program arguments, and an unchecked NumberFormatException is thrown if an argument cannot be converted to an int value. The astute reader will notice that the code for handling these two exceptions is the same in the body of the respective catch clauses. In order to avoid such code duplication, one might be tempted to replace the two catch clauses with a single catch clause that catches a more general exception, for example:

Click here to view code image

catch (RuntimeException rte) { // NOT RECOMMENDED!
  System.out.println(rte);
  System.out.println(“Usage: java Average9 <sum of values> <no. of values>”);
}

This is certainly not recommended, as specific exceptions are to be preferred over general exceptions, not the least because a more general exception type might unintentionally catch more exceptions than intended.

Example 7.9 Using Multiple catch Clauses

Click here to view code image

// File: IntegerDivisionByZero.java
public class IntegerDivisionByZero extends Exception {
  IntegerDivisionByZero() { super(“Integer Division by Zero”); }
}

Click here to view code image

// File: Average9.java
public class Average9 {
  public static void main(String[] args) {
    try {                                                     // (1)
      int sum         = Integer.parseInt(args[0]);            // (2)
      int numOfValues = Integer.parseInt(args[1]);            // (3)
      printAverage(sum, numOfValues);                         // (4)
    } catch (ArrayIndexOutOfBoundsException aioob) {          // (5) uni-catch
      System.out.println(aioob);
      System.out.println(“Usage: java Average9 <sum of values> <no. of values>”);
    } catch (NumberFormatException nfe) {                     // (6) uni-catch
      System.out.println(nfe);
      System.out.println(“Usage: java Average9 <sum of values> <no. of values>”);
    } catch (IntegerDivisionByZero idbz) {                    // (7) uni-catch
      idbz.printStackTrace();
      System.out.println(“Exception handled in main().”);
    } finally {                                               // (8)
      System.out.println(“Finally done in main().”);
    }
    System.out.println(“Exit main().”);                       // (9)
  }
  public static void printAverage(int totalSum, int totalCount)
      throws IntegerDivisionByZero {
    int average = computeAverage(totalSum, totalCount);
    System.out.println(“Average = ” +
        totalSum + ” / ” + totalCount + ” = ” + average);
    System.out.println(“Exit printAverage().”);
  }
  public static int computeAverage(int sum, int count)
      throws IntegerDivisionByZero {
    System.out.println(“Computing average.”);
    if (count == 0)
      throw new IntegerDivisionByZero();
    return sum/count;
  }
}

Running the program:

Click here to view code image

>
java Average9 100 twenty

java.lang.NumberFormatException: For input string: “twenty”
Usage: java Average9 <sum of values> <no. of values>
Finally done in main().
Exit main().

Running the program:

Click here to view code image

>
java Average9 100

java.lang.ArrayIndexOutOfBoundsException: 1
Usage: java Average9 <sum of values> <no. of values>
Finally done in main().
Exit main().

The multi-catch clause provides the solution, allowing specific exceptions to be declared and avoiding duplicating the same code for the body of the catch clauses. The syntax of the multi-catch clause is as follows:

Click here to view code image

catch (
exception_type
1
|
exception_type
2
|…|
exception_type
k
parameter
) {
statements
}

The multi-catch clause still has a single parameter, but now a list of exception types, delimited by the vertical bar (|), can be specified as the types for this parameter. This list defines a union of alternatives that are the exception types which the multi-catch clause can handle. The statements in the body of the multi-catch clause will be executed when an object of any of the specified exception types is caught by the multi-catch clause.

The multiple catch clauses at (5) and (6) in Example 7.9 have been replaced with a multi-catch clause at (5) in Example 7.10:

Click here to view code image

catch (ArrayIndexOutOfBoundsException |                  // (5) multi-catch
       NumberFormatException ep) {
  System.out.println(ep);
  System.out.println(“Usage: java Average10 <sum of values> <no. of values>”);
}

The multi-catch clause in Example 7.10 is semantically equivalent to the two uni-catch clauses in Example 7.9, and we can expect the same program behavior in both examples.

Example 7.10 Using the Multi-catch Clause

Click here to view code image

// File: Average10.java
public class Average10 {
  public static void main(String[] args) {
    try {                                                      // (1)
      int sum = Integer.parseInt(args[0]);                     // (2)
      int numOfValues = Integer.parseInt(args[1]);             // (3)
printAverage(sum, numOfValues);                          // (4)
    } catch (ArrayIndexOutOfBoundsException |                  // (5) multi-catch
             NumberFormatException ep) {
      System.out.println(ep);
      System.out.println(“Usage: java Average10 <sum of values> <no. of values>”);
    } catch (IntegerDivisionByZero idbz) {                     // (6) uni-catch
      idbz.printStackTrace();
      System.out.println(“Exception handled in main().”);
    } finally {                                                // (7)
      System.out.println(“Finally done in main().”);
    }
    System.out.println(“Exit main().”);                        // (8)
  }
  public static void printAverage(int totalSum, int totalCount)
      throws IntegerDivisionByZero {
    // See Example 7.9.
  }
  public static int computeAverage(int sum, int count)
      throws IntegerDivisionByZero {
    // See Example 7.9.
  }
}

A few remarks are in order regarding the alternatives of a multi-catch clause. There should be no subtype–supertype relationship between any of the specified exception types in the alternatives of a multi-catch clause. The following multi-catch clause will not compile, as ArrayIndexOutOfBoundsException is a subtype of IndexOutOfBoundsException:

Click here to view code image

catch (IndexOutOfBoundsException |                  // Compile-time error!
       ArrayIndexOutOfBoundsException e) {
  // …
}

The parameter of a multi-catch clause is also considered to be implicitly final, and therefore cannot be assigned to in the body of the multi-catch clause. In a uni-catch clause, the parameter is considered to be effectively final if it does not occur on the left-hand side of an assignment in the body of the uni-catch clause.

Click here to view code image

try {
  // Assume appropriate code to throw the right exceptions.
} catch (NumberFormatException |
         IndexOutOfBoundsException e) {    // Parameter is final.
  e = new ArrayIndexOutOfBoundsException();// Compile-time error!
                                           // Cannot assign to final parameter e.
} catch (IntegerDivisionByZero idbz) {     // Parameter is effectively final.
  idbz.printStackTrace();
} catch (IOException ioe) {                // Parameter is not effectively final.
  ioe = new FileNotFoundException(“No file.”);
}

Disallowing any subtype–supertype relationship between alternatives and the parameter being final in a multi-catch clause or effectively final in a uni-catch clause allows the compiler to perform precise exception handling analysis.

The compiler also generates effective bytecode for a single exception handler corresponding to all the alternatives in a multi-catch clause, in contrast to generating bytecode for multiple exception handlers for uni-catch clauses that correspond to the multi-catch clause.

Leave a Reply

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