Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java overriding throws clause

I'm learning for OCJP exam by reading the book written by S G Ganesh and Tushar Sharma. At page 346 there is a text that says:

What if you try changing the throws clause? There are many ways to change the throws clause in the overriding method, including the following:
a. Not providing any throws clause.
b. Listing more general checked exceptions to throw.
c. Listing more checked exceptions in addition to the given checked exception(s) in the base method.
If you attempt any of these three cases, you’ll get a compiler error. For example, try not providing the throws clause in the readIntFromFile() method in the class that implements the IntReader interface.

public int readIntFromFile() {
    Scanner consoleScanner = new Scanner(new File("integer.txt"));
    return consoleScanner.nextInt();
}

You’ll get this compiler error: “unreported exception FileNotFoundException; must be caught or declared to be thrown.”
To summarize, the base class method’s throws clause is a contract that it provides to the caller of that method:
it says that the caller should handle the listed exceptions or declare those exceptions in its throws clause. When overriding the base method, the derived method should also adhere to that contract. The caller of the base method is prepared to handle only the exceptions listed in the base method, so the overriding method cannot throw more general or other than the listed checked exceptions.
However, note that this discussion that the derived class method’s throws clause should follow the contract for the base method’s throws clause is limited to checked exceptions. Unchecked exceptions can still be added or removed from the contract when compared to the base class method’s throws clause. For example, consider the following:

public int readIntFromFile() throws IOException, NoSuchElementException {
    Scanner consoleScanner = new Scanner(new File("integer.txt"));
    return consoleScanner.nextInt();
}

This is an acceptable throws clause since NoSuchElementException can get thrown from the readIntFromFile() method. This exception is an unchecked exception, and it gets thrown when the nextInt() method could not read an integer from the file. This is a common situation, for example, if you have an empty file named integer.txt; an attempt to read an integer from this file will result in this exception.

I'm a little bit concerned about the point "a.". It says that if you don't provide any throws clause the code won't compile. But when I was learning for OCA, I remember I read that you can provide the same throws clause, a more specific Exception or no throws clause at all and the code will still compile and these are available only for Checked Exceptions. I've tried to do some tests but I can't get “unreported exception FileNotFoundException; must be caught or declared to be thrown.”. I remember I saw it but I don't know in which conditions.

like image 819
Mike Avatar asked Sep 05 '15 10:09

Mike


1 Answers

Counterexample point A

The book is wrong on point A.

The following code compiles perfectly fine:

class A {
    void method() throws GeneralSecurityException {
    }
}

class B extends A {
    void method() {
    }
}

Class B clearly invalidates point A.

Counterexample point C

The book is also oversimplifying point C: the code is correct as long as the thrown exceptions are subclasses of the checked exceptions that are already thrown.

class C extends A {
    void method() throws NoSuchAlgorithmException, InvalidKeyException {
    }
}

In the code NoSuchAlgorithmException and InvalidKeyException are subclasses of GeneralSecurityException.

Class C shows the oversimplification of point C.

JLS references

The following is states in the The Java Language Specification, Java SE 8 Edition, chapter 11.2:

...

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).

...

The reference in 8.4.8.3 reads:

...

  • If m2 has a throws clause that mentions any checked exception types, then m1 must have a throws clause, or a compile-time error occurs.
  • For every checked exception type listed in the throws clause of m2, that same exception class or one of its supertypes must occur in the erasure (§4.6) of the throws clause of m1; otherwise, a compile-time error occurs.

...

Discussion of the JLS text

These JLS chapters makes sense. In the end the code calling a method that declares a specific checked exception would have code handling that particular checked exception. If another checked exception is thrown by a method of a child class instance the checked exception is unlikely to be handled. On the other hand, the caller is OK if a method does not throw any exceptions that the caller is expecting; the exception handling code will simply not be invoked.

Code should always expect to receive runtime exceptions, so RuntimeException based exceptions are exempt from the compile time check.

Rule of thumb

As long as you only throw exceptions that are expected by the caller the code should be OK.

like image 171
Maarten Bodewes Avatar answered Oct 27 '22 03:10

Maarten Bodewes