Exception restrictions


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Bruce Eckel's Thinking in Java Contents | Prev | Next

//: StormyInning.java
// Overridden methods may throw only the 
// exceptions specified in their base-class 
// versions, or exceptions derived from the 
// base-class exceptions.
class BaseballException extends Exception {}
class Foul extends BaseballException {}
class Strike extends BaseballException {}
abstract class Inning {
  Inning() throws BaseballException {}
  void event () throws BaseballException {
   // Doesn't actually have to throw anything
  abstract void atBat() throws Strike, Foul;
  void walk() {} // Throws nothing
class StormException extends Exception {}
class RainedOut extends StormException {}
class PopFoul extends Foul {}
interface Storm {
  void event() throws RainedOut;
  void rainHard() throws RainedOut;
public class StormyInning extends Inning 
    implements Storm {
  // OK to add new exceptions for constructors,
  // but you must deal with the base constructor
  // exceptions:
  StormyInning() throws RainedOut, 
    BaseballException {}
  StormyInning(String s) throws Foul, 
    BaseballException {}
  // Regular methods must conform to base class:
//! void walk() throws PopFoul {} //Compile error
  // Interface CANNOT add exceptions to existing
  // methods from the base class:
//! public void event() throws RainedOut {}
  // If the method doesn't already exist in the
  // base class, the exception is OK:
  public void rainHard() throws RainedOut {}
  // You can choose to not throw any exceptions,
  // even if base version does:
  public void event() {}
  // Overridden methods can throw 
  // inherited exceptions:
  void atBat() throws PopFoul {}
  public static void main(String[] args) {
    try {
      StormyInning si = new StormyInning();
    } catch(PopFoul e) {
    } catch(RainedOut e) {
    } catch(BaseballException e) {}
    // Strike not thrown in derived version.
    try {
      // What happens if you upcast?
      Inning i = new StormyInning();
      // You must catch the exceptions from the
      // base-class version of the method:
    } catch(Strike e) {
    } catch(Foul e) {
    } catch(RainedOut e) {
    } catch(BaseballException e) {}
} ///:~ 

In Inning, you can see that both the constructor and the event( ) method say they will throw an exception, but they never do. This is legal because it allows you to force the user to catch any exceptions that you might add in overridden versions of event( ). The same idea holds for abstract methods, as seen in atBat( ).

The interface Storm is interesting because it contains one method ( event( ))that is defined in Inning, and one method that isn’t. Both methods throw a new type of exception, RainedOut. When StormyInning extends Inning and implements Storm , you’ll see that the event( ) method in Storm cannot change the exception interface of event( ) in Inning. Again, this makes sense because otherwise you’d never know if you were catching the correct thing when working with the base class. Of course, if a method described in an interface is not in the base class, such as rainHard( ), then there’s no problem if it throws exceptions.

It’s useful to realize that although exception specifications are enforced by the compiler during inheritance, the exception specifications are not part of the type of a method, which is comprised of only the method name and argument types. Therefore, you cannot overload methods based on exception specifications. In addition, because an exception specification exists in a base-class version of a method doesn’t mean that it must exist in the derived-class version of the method, and this is quite different from inheriting the methods (that is, a method in the base class must also exist in the derived class). Put another way, the “exception specification interface” for a particular method may narrow during inheritance and overriding, but it may not widen – this is precisely the opposite of the rule for the class interface during inheritance.

[43] ANSI/ISO C++ added similar constraints that require derived-method exceptions to be the same as, or derived from, the exceptions thrown by the base-class method. This is one case in which C++ is actually able to check exception specifications at compile time.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date