Приветствую всех изучающих 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() }
Очевидно, приведенные выше ограничения и фичи будет не лишним учитывать при проектировании иерархии классов для очередного проекта.
