7.5 The throws Clause
A throws clause can be specified in a method or a constructor header to declare any checked exceptions that can be thrown by a statement in the body of a method or a constructor. It is declared immediately preceding the body of the method or the constructor.
… throws
ExceptionType
1
,
ExceptionType
2
,…,
ExceptionType
n
{ /* Body */ }
Each ExceptionTypei is an exception type (i.e., a Throwable or one of its subclasses), although usually only checked exceptions are specified. The compiler enforces that if a checked exception can be thrown from the body of the method or the constructor, then either the type of this exception or a supertype of its exception type is specified in the throws clause of the method or the constructor. The throws clause can specify unchecked exceptions, but this is seldom done and the compiler does not enforce any restrictions on their usage.
The throws clause is part of the contract that a method or a constructor offers to its clients. The throws clause can specify any number of exception types in any order, even those that are not thrown by the method or the constructor. The compiler simply ensures that any checked exception that can actually be thrown in the method or constructor body is covered by the throws clause. Of course, any caller of the method or constructor cannot ignore the checked exceptions specified in the throws clause.
In a method or a constructor, a checked exception can be thrown directly by a throw statement, or indirectly by calling other methods or constructors that can throw a checked exception. If a checked exception is thrown, the code must obey the following rule (known by various names: catch-or-declare rule, handle-or-declare rule, catch-or-specify requirement):
- Either use a try block and catch the checked exception in a catch block and deal with it
- Or explicitly allow propagation of the checked exception to its caller by declaring it in the throws clause
Note that catching and dealing with a checked exception does not necessarily imply resumption of normal execution. A catch clause can catch the checked exception and choose to throw some other exception or even the same exception that is either unchecked or declared in the throws clause (p. 401). This rule ensures that a checked exception will be dealt with, regardless of the path of execution. This aids development of robust programs, as allowance can be made for many contingencies.
In Example 7.8, a new checked exception is defined, where the checked exception class IntegerDivisionByZero extends the Exception class. The method call at (2) in the try block at (1) results in the printAverage() method at (6) to be executed. The method call at (7) results in the computeAverage() method at (8) to be executed.
In the if statement at (9), the method computeAverage() throws the checked exception IntegerDivisionByZero. Neither the computeAverage() method nor the printAverage() method catches the exception, but instead throws it to the caller, as declared in the throws clauses in their method headers at (6) and (8). The exception propagates to the main() method. Since the printAverage() method was called from the context of the try block at (1) in the main() method, the exception is successfully caught by its catch clause at (3). The exception is handled and the finally clause at (4) is executed, with normal execution resuming from (5). If the method main() did not catch the exception, it would have to declare this exception in a throws clause. In that case, the exception would end up being handled by the default exception handler.
Example 7.8 The throws Clause
// File: IntegerDivisionByZero.java
public class IntegerDivisionByZero extends Exception {
IntegerDivisionByZero() { super(“Integer Division by Zero”); }
}
// File: Average8.java
public class Average8 {
public static void main(String[] args) {
try { // (1)
printAverage(100, 0); // (2)
} catch (IntegerDivisionByZero idbz) { // (3)
idbz.printStackTrace();
System.out.println(“Exception handled in main().”);
} finally { // (4)
System.out.println(“Finally done in main().”);
}
System.out.println(“Exit main().”); // (5)
}
public static void printAverage(int totalSum, int totalCount)
throws IntegerDivisionByZero { // (6)
int average = computeAverage(totalSum, totalCount); // (7)
System.out.println(“Average = ” +
totalSum + ” / ” + totalCount + ” = ” + average);
System.out.println(“Exit printAverage().”);
}
public static int computeAverage(int sum, int count)
throws IntegerDivisionByZero { // (8)
System.out.println(“Computing average.”);
if (count == 0) // (9)
throw new IntegerDivisionByZero();
return sum/count; // (10)
}
}
Output from the program:
Computing average.
IntegerDivisionByZero: Integer Division By Zero
at Average8.computeAverage(Average8.java:27)
at Average8.printAverage(Average8.java:17)
at Average8.main(Average8.java:5)
Exception handled in main().
Finally done in main().
Exit main().
As mentioned earlier, the exception type specified in the throws clause can be a superclass of the actual exceptions thrown—that is, the exceptions thrown must be assignable to the type of the exceptions specified in the throws clause. If a method or a constructor can throw a checked exception, then the throws clause must declare its exception type or a supertype of its exception type; otherwise, a compile-time error will occur. In the printAverage() method, the superclass Exception of the subclass IntegerDivisionByZero could be specified in the throws clause of the method. This would also entail that the main() method either catch an Exception or declare it in a throws clause.
public static void main(String[] args) throws Exception {
/* … */
}
public static void printAverage(int totalSum, int totalCount) throws Exception {
/* … */
}
It is generally considered bad programming style to specify exception superclasses in the throws clause when the actual exceptions thrown are instances of their subclasses. It is also recommended to use the @throws tag in a Javadoc comment to document the checked exceptions that a method or a constructor can throw, together with any unchecked exceptions that might also be relevant to catch.