Compile-Time Checking of Exceptions

11.2 Compile-Time Checking of Exceptions

The Java programming language requires that a program contains handlers for checked exceptions which can result from execution of a method or constructor. For each checked exception which is a possible result, the throws clause for the

EXCEPTIONS Compile-Time Checking of Exceptions 11.2

method (§8.4.6) or constructor (§8.8.5) must mention the class of that exception or one of the superclasses of the class of that exception (§11.2.3).

This compile-time checking for the presence of exception handlers is designed to reduce the number of exceptions which are not properly handled. The checked exception classes (§11.1.1) named in the throws clause are part of the contract between the implementor and user of the method or constructor. The throws clause of an overriding method may not specify that this method will result in throwing any checked exception which the overridden method is not permitted, by its throws clause, to throw (§8.4.8.3).

When interfaces are involved, more than one method declaration may be overridden by a single overriding declaration. In this case, the overriding declaration must have a throws clause that is compatible with all the overridden declarations (§9.4.1).

The unchecked exception classes (§11.1.1) are exempted from compile-time checking.

Of the unchecked exception classes, error classes are exempted because they can occur at many points in the program and recovery from them is difficult or impossible. A program declaring such exceptions would be cluttered, pointlessly. Sophisticated programs may yet wish to catch and attempt to recover from some of these conditions.

Of the unchecked exception classes, runtime exception classes are exempted because, in the judgment of the designers of the Java programming language, having to declare such exceptions would not aid significantly in establishing the correctness of programs. Many of the operations and constructs of the Java programming language can result in exceptions at run-time. The information available to a Java compiler, and the level of analysis a compiler performs, are usually not sufficient to establish that such run-time exceptions cannot occur, even though this may be obvious to the programmer. Requiring such exception classes to

be declared would simply be an irritation to programmers. For example, certain code might implement a circular data structure that, by construction,

can never involve null references; the programmer can then be certain that a NullPointerException cannot occur, but it would be difficult for a Java compiler to prove it. The theorem-proving technology that is needed to establish such global properties of data structures is beyond the scope of this specification.

We say that a statement or expression can throw a checked exception class E if, according to the rules in §11.2.1 and §11.2.2, the execution of the statement or

expression can result in an exception of class E being thrown.

We say that a catch clause can catch its catchable exception class(es). The catchable exception class of a uni- catch clause is the declared type of its

exception parameter (§14.20).

11.2.1 Exception Analysis of Expressions EXCEPTIONS

The catchable exception classes of a multi- catch clause are the alternatives in the union that denotes the type of its exception parameter (§14.20).

11.2.1 Exception Analysis of Expressions

A class instance creation expression (§15.9) can throw an exception class E iff either:

• The expression is a qualified class instance creation expression and the

qualifying expression can throw E ; or • Some expression of the argument list can throw E ; or

• E is determined to be an exception class of the throws clause of the constructor that is invoked (§15.12.2.6); or

• The class instance creation expression includes a ClassBody, and some instance initializer block or instance variable initializer expression in the ClassBody can throw E .

A method invocation expression (§15.12) can throw an exception class E iff either: • The method to be invoked is of the form Primary.Identifier and the Primary

expression can throw E ; or • Some expression of the argument list can throw E ; or

• E is determined to be an exception class of the throws clause of the method that is invoked (§15.12.2.6).

For every other kind of expression, the expression can throw an exception class E

iff one of its immediate subexpressions can throw E .

11.2.2 Exception Analysis of Statements

A throw statement (§14.18) whose thrown expression has static type E and is not

a final or effectively final exception parameter can throw E or any exception class that the thrown expression can throw.

For example, the statement throw new java.io.FileNotFoundException(); can throw java.io.FileNotFoundException only. Formally, it is not the case that it "can throw" a subclass or superclass of java.io.FileNotFoundException .

A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:

EXCEPTIONS Exception Checking 11.2.3

• E is an exception class that the try block of the try statement which declares

C can throw; and • E is assignment compatible with any of C 's catchable exception classes; and

• E is not assignment compatible with any of the catchable exception classes of the

catch clauses declared to the left of C in the same try statement.

A try statement (§14.20) can throw an exception class E iff either:

• The try block can throw E , or an expression used to initialize a resource (in a try -with-resources statement) can throw E , or the automatic invocation of the close() method of a resource (in a try -with-resources statement) can throw E ,

and E is not assignment compatible with any catchable exception class of any catch clause of the try statement, and either no finally block is present or the finally block can complete normally; or

• Some catch block of the try statement can throw E and either no finally block is present or the finally block can complete normally; or

•A finally block is present and can throw E .

An explicit constructor invocation statement (§8.8.7.1) can throw an exception class E iff either:

• Some expression of the constructor invocation's parameter list can throw E ; or • E is determined to be an exception class of the throws clause of the constructor

that is invoked (§15.12.2.6). Any other statement S can throw an exception class E iff an expression or statement

immediately contained in S can throw E .

11.2.3 Exception Checking

It is a compile-time error if a method or constructor body can throw some exception class E when E is a checked exception class and E is not a subclass of some class declared in the throws clause of the method or constructor.

It is a compile-time error if a class variable initializer (§8.3.2) or static initializer (§8.7) of a named class or interface can throw a checked exception class.

It is a compile-time error if an instance variable initializer or instance initializer of a named class can throw a checked exception class unless that exception class or one of its superclasses is explicitly declared in the throws clause of each constructor of its class and the class has at least one explicitly declared constructor.

11.2.3 Exception Checking EXCEPTIONS

Note that no compile-time error is due if an instance variable initializer or instance initializer of an anonymous class (§15.9.5) can throw an exception class. In a named class, it is the responsibility of the programmer to propagate information about which exception classes can be thrown by initializers, by declaring a suitable throws clause on any explicit constructor declaration. This relationship between the checked exception classes thrown by a class's initializers and the checked exception classes declared by a class's constructors is assured implicitly for an anonymous class declaration, because no explicit constructor declarations are possible and a Java compiler always generates a constructor with a suitable throws clause for that anonymous class declaration based on the checked exception classes that its initializers can throw.

It is a compile-time error if a catch clause can catch checked exception class E 1 and it is not the case that the try block corresponding to the catch clause can throw a checked exception class that is a subclass or superclass of E 1 , unless E 1 is Exception or a superclass of Exception .

It is a compile-time error if a catch clause can catch (§11.2) checked exception class E 1 and a preceding catch clause of the immediately enclosing try statement

can catch E 1 or a superclass of E 1 .

A Java compiler is encouraged to issue a warning if a catch clause can catch (§11.2) checked exception class E 1 and the try block corresponding to the catch clause can throw checked exception class E 2 , a subclass of E 1 , and a preceding catch clause of the immediately enclosing try statement can catch checked exception class E 3 where E 2 <: E 3 <: E 1 .

Example 11.2.3-1. Catching Checked Exceptions

import java.io.*;

class StaticallyThrownExceptionsIncludeSubtypes { public static void main(String[] args) {

try { throw new FileNotFoundException(); } catch (IOException ioe) {

// Legal in Java SE 6 and 7. "catch IOException" // catches IOException and any subtype.

try { throw new FileNotFoundException();

// Statement "can throw" FileNotFoundException. // It is not the case that statement "can throw" // a subtype or supertype of FileNotFoundException.

} catch (FileNotFoundException fnfe) { // Legal in Java SE 6 and 7. } catch (IOException ioe) {

// Legal in Java SE 6 and 7, but compilers are // encouraged to throw warnings as of Java SE 7. // All subtypes of IOException that the try block // can throw have already been caught.

EXCEPTIONS Run-Time Handling of an Exception 11.3

try { m(); // Method m's declaration says "throws IOException". // m "can throw" IOException. It is not the case // that m "can throw" a subtype or supertype of // IOException, e.g. Exception, though Exception or // a supertype of Exception can always be caught.

} catch (FileNotFoundException fnfe) { // Legal in Java SE 6 and 7, because the dynamic type // of the IOException might be FileNotFoundException.

} catch (IOException ioe) { // Legal in Java SE 6 and 7. } catch (Throwable t) { // Legal in Java SE 6 and 7. } }

static void m() throws IOException { throw new FileNotFoundException(); } }

By the rules above, each alternative in a multi- catch clause (§14.20) must be able to catch some exception class thrown by the try block and uncaught by previous catch clauses. For example, the second catch clause below would cause a compile-time error because exception analysis determines that SubclassOfFoo is already caught by the first catch clause:

try { ... } catch (Foo f) { ... } catch (Bar | SubclassOfFoo e) { ... }