Книга е още в много ранна фаза на написване


Ограничения при изключенията



страница54/73
Дата25.07.2016
Размер13.53 Mb.
#6732
1   ...   50   51   52   53   54   55   56   57   ...   73

Ограничения при изключенията


Когато подтискате метод може да изхвърляте само изключенията, зададени за ме­тода от базовия клас. Това е полезно ограничение, понеже води до това, че код който работи с базовия клас ще работи също така и с който и да е извлечен клас (основна концепция в ООП, разбира се), включително изключенията.

Този пример демонстрира видовете наложени ограничения (по време на ко­м­пи­ла­ция) за изключенията:

//: c09: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();

si.atBat();

} 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();

i.atBat();

// 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) {}

}

} ///:~


В Inning може да видите че както конструкторът така и методът event( ) казват че ще изхвърлят изключение но не го правят. Това е законно понеже кара потребителя да прихване всяко изключение което би могло да се появи в под­тис­натите версии на event( ). Същата идея важи и за abstract методи, както се виж­да в atBat( ).

interface Storm е интересен с това, че съдържа един метод (event( )) дефиниран в Inning и един метод който не е. И двата метода изхвърлят нов тип изклю­че­ние, RainedOut. Когато StormyInning extends Inning и implements Storm, ще ви­дите че методът event( ) в Storm не може да смени интерфейса на из­клю­че­ния­та event( ) в Inning. Отново това има смисъл понеже иначе никога няма да е си­гурно дали имате провилното нещо когато хващате изключение от базовия клас. Разбира се ако метод описан в interface не е в базовия клас, както rainHard( ), няма проблеми ако той изхвърля изключения.

Ограничението на изключенията не се прилага за конструкторите. В StormyInning може да видите, че конструкторът може да изхвърли всичко ка­кво­то иска, без значение какво изхвърля конструкторът на базовия клас. Обаче тъй като базовият конструктор се вика винаги по един или друг начин (тука кон­структор по подразбиране се вика автоматично), конструкторът на из­вле­че­ния клас трябва да декларира всички изключения на конструктора на базовия клас в своята спецификация на изключения.

Причината да не се компилира StormyInning.walk( ) е че изхвърля изключение, до­като Inning.walk( ) не. Ако това беше допустимо, можеше да се напише код кой­то вика Inning.walk( ) и той нямаше да е нужно да обработи изключения, но ко­гато замените обект от клас низвлечен от Inning, биха били изхвърляни из­клю­чения и кодът щеше да се скапе. Чрез заставянето на методите на из­вле­че­ния клас да отговарят на спецификацията на изключенията на базовия клас се об­служва взаимозаменяемостта на методите.

Подтиснатия event( ) метод показва, че версията на метод в извлечен клас може да избере въобще да не изхвърля изключения, макар и версията на базовия клас да го прави. Отново това е необходимото за да работи с всякакъв наследен код. По­добна логика важи за atBat( ), който изхвърля PopFoul, изключение из­вле­че­но от Foul изхвърляно от базовата версия на atBat( ). По този начин ако някой на­пише кад кайто работи с Inning и вика atBat( ), те трябва да хванат Foul из­клю­чението. Понеже PopFoul е извлечено от Foul, обработчикът ще хване и PopFoul.

Последната интересна точка е в main( ). Тук се вижда че ако се разправяте точ­но с StormyInning обект, компилаторът ви заставя да хващате изключенията спе­цифични точно за него, но ако направите ъпкаст към базовия клас ком­пи­ла­то­рът (коректно) ви заставя да хващате изключенията на базовия тип. Всички те­зи ограничения довеждат до много по-добър код за обработка на из­клю­че­ния.3

Полезно е да се разбере, че макар и ограниченията при изключенията да се на­ла­гат от компилатора чрез наследяване, спецификациите на ограничения не са част от даден тип, който е съставен само от името и типовете на аргументите. За­това не може да се пренатоварват методи чрез спецификацията на из­клю­че­ния. Освен това ако има спецификация на изключенията в базовия метод това не значи че непременно тя съществува и в извлечения, а това е доста различно от наследяване на методи (тоест, метод в базовия клас трябва също да съ­ще­ству­ва и в извлечения клас). С други думи казано, “интерфейсът на спе­ци­фи­ка­ция на изключенията” за конкретен метод може да се стеснява в процеса на на­сле­дяване и подтискане, но не може да се разширява – това е точно наопаки на ин­терфейса на базовия и извлечения клас при наследяване.





Сподели с приятели:
1   ...   50   51   52   53   54   55   56   57   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница