Приветствую всех изучающих Java!
Как известно исключения в Java, при наследовании подчиняются требованию сужения спецификации, а не ее расширения, в отличие от обычных классов.
В книге Bruce Eckel «Thinking in Java, 4 ed.» приведено описание ограничений, накладываемых при использовании исключений. Пример кода описывает наследование от базового класса и одновременную реализацию интерфейса, причем у обоих имеются методы с одинаковой сингатурой, но разной спецификацией исключений. Попытки реализации методов интерфейса пересекаются с попытками одновременного переопределения методов базового класса, в результате которых делается упор на недопущение расширения спецификации исключений. Упрощенный пример кода, доносящий идею:
Пример можно дополнить другими вариантами спецификаций исключений, перебрав некоторые интересные сочетания:
Очевидно, приведенные выше ограничения и фичи будет не лишним учитывать при проектировании иерархии классов для очередного проекта.
Как известно исключения в Java, при наследовании подчиняются требованию сужения спецификации, а не ее расширения, в отличие от обычных классов.
В книге Bruce Eckel «Thinking in Java, 4 ed.» приведено описание ограничений, накладываемых при использовании исключений. Пример кода описывает наследование от базового класса и одновременную реализацию интерфейса, причем у обоих имеются методы с одинаковой сингатурой, но разной спецификацией исключений. Попытки реализации методов интерфейса пересекаются с попытками одновременного переопределения методов базового класса, в результате которых делается упор на недопущение расширения спецификации исключений. Упрощенный пример кода, доносящий идею:
class BaseBallException extends Exception{}
class Foul extends BaseBallException{}
class Strike extends BaseBallException{}
abstract class Inning {
//-----Methods----
public Inning() throws BaseBallException{}
public void event() throws BaseBallException{}
public abstract void atBat() throws Strike, Foul;
}
class StormException extends Exception{}
class RainedOut extends StormException{}
class PopFoul extends Foul{}
interface Storm {
public void event() throws RainedOut;
}
class StormyInning extends Inning implements Storm {
//--------Methods-----
public StormyInning() throws RainedOut, BaseBallException{}
public StormyInning(String str) throws Foul, BaseBallException{}
/**ошибка компиляции - реализация метода Storm.event() throws RainedOut пытается изменить спецификацию
* исключений метода Inning.event() throws BaseBallException на новое исключение RainedOut*/
//! public void event() throws RainedOut{}
/**требуется переопределение метода event() с пустой спецификацией исключений - это безболезненно в
* силу сужения спецификации и необходимо для реализации интерфейса.
* В данном случае - единственный вариант*/
public void event() {}
public void atBat() throws PopFoul {}
}
Пример можно дополнить другими вариантами спецификаций исключений, перебрав некоторые интересные сочетания:
class BaseBallException extends Exception{}
class Foul extends BaseBallException{}
class Strike extends BaseBallException{}
class LightStrike extends Strike{}
class TwistedLightStrike extends LightStrike{}
abstract class Inning {
//-----Methods----
public Inning() throws BaseBallException{}
public void event() throws BaseBallException{}
public void event1() throws BaseBallException{}
public void event2() {}
public void event3() throws RainedOut{}
public void event4() throws Strike{}
public void event5() throws LightStrike{}
}
class StormException extends Exception{}
class RainedOut extends StormException{}
class Drizzle extends RainedOut{}
class PopFoul extends Foul{}
interface Storm {
public void event() throws RainedOut;
public void event1();
public void event2() throws RainedOut;
public void event3() throws RainedOut;
public void event4() throws LightStrike;
public void event5() throws Strike;
}
class StormyInning extends Inning implements Storm {
//--------Methods-----
public StormyInning() throws RainedOut, BaseBallException{}
public StormyInning(String str) throws Foul, BaseBallException{}
/**ошибка компиляции - реализация метода Storm.event() throws RainedOut пытается изменить спецификацию
* исключений метода Inning.event() throws BaseBallException на новое исключение RainedOut*/
//! public void event() throws RainedOut{}
/**ошибка компиляции - реализация метода Storm.event() throws RainedOut c заменой исключния RainedOut на
* BaseBallException является попыткой изменить спецификацию исключений этого метода*/
//! public void event() throws BaseBallException{}
/**ошибка компиляции - смешаный вариант не проходит по причине обоюдных попыток расширить
* спецификацию исключений*/
//! public void event() throws RainedOut, BaseBallException{}
/**Единственный и необходимый вариант*/
public void event() {}
/**ошибка компиляции - метод интерфейса Storm.event1() не допускает расширения спецификации*/
//! public void event1() throws BaseBallException {}
/**Единственный и необходимый вариант - интерфейс требует реализации метода Storm.event1() и
* только с чистой спецификацией*/
public void event1(){}
/**ошибка компиляции - метод абстрактного базового класса Inning.event() сопротивляется расширению
* спецификации*/
//! public void event2() throws RainedOut{}
/**Единственный однако не необходимый вариант реализации интерфейсного метода.
* Реализация может отсутствовать вовсе т.к. абстрактный базовый класс реализует интерфейсный метод
* Storm.event2() throws RainedOut с сужением спецификации исключений*/
//public void event2(){}
/**Реализация метода Storm.event3() throws RainedOut может отсутствовать вовсе - абстрактный базовый
* класс реализует интерфейсный метод Storm.event3() throws RainedOut, спецификации исключений
* совпадают. Но можно и реализовать метод с исходной спецификацией исключений*/
//public void event3() throws RainedOut{}
/**также можно в соответствии с иерархией исключений реализовывать методы с последовательным
* сужением спецификации исключений вплоть до чистой*/
//public void event3() throws Drizzle{}
//public void event3() {}
/**Теперь ловим плечо, на котором может быть реализован метод event4()*/
/**Реализация метода event4() требуется т.к. абстрактный базовый класс расширяет, а не сужает
* спецификацию исключений*/
/**ошибка компиляции - попытка расширить спецификацию исключений метода интерфейса Storm.event4()*/
//! public void event4() throws Strike{}
/**Работает - спецификация метода абстрактного класса сузилась, интерфейса - соответствует*/
//public void event4() throws LightStrike{}
/**Работает - здесь и далее обе спецификации исключений сузились*/
//public void event4() throws TwistedLightStrike{}
public void event4() {}
/**Идея как и для event4(), но на этот раз реализации не требуется - абстрактный класс сужает спецификацию
* и реализует интерфейсный метод*/
//! public void event5() throws Strike{}
//public void event5() throws LightStrike{}
//public void event5() throws TwistedLightStrike{}
//public void event5()
}
Очевидно, приведенные выше ограничения и фичи будет не лишним учитывать при проектировании иерархии классов для очередного проекта.