Throws Exception Declaration Does Not Consider Inheritance

This is actually not a design flaw, but a misunderstanding of language specification, and the reason for this.

The thing is simple: a derived class may throw the same exception(s) or narrower exceptions then those specified in the base method. The reason for this is simple: pointers to the derived class should be safe to use in contexts where pointers of the base class are expected.

The confusion seems to center around why the absence of a throws clause in the derived method doesn't default to the base method specification, so that (presumably) we don't have to retype the throws clause from the base class.

But if we assume this later behavior, the derived class will not be able to narrow the exception specification to none. Maybe a derived class manages to do the operation without any exception; why should we then burden the clients who know that they have a derived class object with catching exceptions specified only in the base class that will never be thrown by the derived? Only this later situation would be a design flaw. The JavaLanguageSpecification is (at least in this regard) as good as it gets. It is also conformant to LiskovSubstitutionPrinciple InformationHiding.


One of the JavaDesignFlaws, in KarlKnechtel's opinion.

Consider the following code:

 abstract class Bar {
   abstract public void wibble() throws Exception;
 }

class FooBar extends Bar { public void wibble() { throw new Exception(); } }

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

Javac complains that wibble() in FooBar neither catches nor declares the Exception that it generates. But it is silent about the Bar class, and happily compiles it. It's perfectly legal to say "throws Exception" there, apparently, but it won't do a damn thing because it's attached to an abstract method.

Perhaps this behaviour is specific to abstract methods being overridden, but it is absurd. The "throws Exception" seems to be completely invisible to the same compiler that reads your comments (to generate deprecation warnings; see DeprecatedInterfaceMethodsCreateUnavoidableWarnings).

[From the JavaLanguageSpecification:]

A method that overrides or hides another method (8.4.6), including methods that implement abstract methods defined in interfaces, may not be declared to throw more checked exceptions than the overridden or hidden method.

More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration n in B overrides or hides a method declaration m in A. If n has a throws clause that mentions any checked exception types, then m must have a throws clause, and for every checked exception type listed in the throws clause of n, that same exception class or one of its superclasses must occur in the throws clause of m; otherwise, a compile-time error occurs.

[FooBar.wibble() can't throw more checked exceptions than Bar.wibble(), but it is free to throw fewer checked exceptions. Since it throws Exception it must declare that in its throws clause. I'm not sure why the original author expects Java to infer the throws clause from the base class.]

Because it hadn't occurred to me that being able to narrow the set of checked exceptions in the subclass. I don't tend to subclass much and most of my subclasses represent implementations anyway, so the caller needs to be able to handle the base class' checked-exception-set anyway. But yes, I can see the problems now resulting from designing it the other way, presumably allowing the subclass to widen the declaration. Just doesn't work. Oh well.

I think I'll go cast a vote for CheckedExceptionsAreOfDubiousValue. This all came about because I was hoping to save myself some typing. -- KarlKnechtel
I'm not sure I understand the confusion. The overriding function provided in the child class must have precisely the same calling signature as the function declaration in the base class. Why? Because if one is providing a base calss definition of a function, one is expecting other routines to call the function from the base class. The routine calling the function from the base class only knows the base class declaration and the overriding function provided in the child class must meet the caller's expectations.


CategoryException | CategoryJava

EditText of this page (last edited June 11, 2005) or FindPage with title or text search