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


Стандартни изключения в Java



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

Стандартни изключения в Java


Java съдържа клас наречен Throwable който описва всяко нещо, което може да бъ­де изхвърлено като изключение. Има два общи типа Throwable обекти (“типа” = “наследени от”). Error представя системни и грешки по време на компилация, за които не се безпокоите за хващането им (освен в специални случаи). Exception е основен тип който може да бъде изхвърлен от всеки от ме­то­дите в стандартните библиотеки класове на Java и от ваши методи и не­спо­лу­ки по време на изпълнение.

Най-добрия начин да се получи поглед върху изключенията е да се разгледа он­лайн Java документацията от http://java.sun.com . (Разбира се, по-лесно е пър­во да се разтовари.) Заслужава си да се направи това веднъж само за да се получи чув­ство за различните видове изключения, но скоро ще забележите че няма не­що кой знае колко различно между две изключения освен името. Също, броят на изключенията в Java продължава да расте; общо взето е безпредметно да се пе­чатат в книга. Всяка библиотека от трети доставчик също би имала свои соб­стве­ни изключения вероятно. Важното нещо тук е да се разбере концепцията и вие така ще направите с изключенията.

java.lang.Exception

Това е основният клас на изключение който може да хване вашата програма. Дру­ги изключения са извлечени от това. Основната идея е имената на из­клю­че­ния­та да отразяват същността на възникналия проблем и да са самого­во­рящи. Не всички изключения са определени в java.lang; някои са за поддръжка на други библиотеки като util, net и io, което може да видите от техните пълни кла­сови имена откъдето са наследени. Например всички IO изключения са на­сле­дени от java.io.IOException.


Специалният случай RuntimeException


Първият пример в тази глава беше

if(t == null)


throw new NullPointerException();

Може да е малко стряскащо да трябва да се проверява всеки път за null всеки ма­нипулатор който се подава на метод (понеже не може да се знае дали е по­да­ден валиден манипулатор). За щастие това не е необходимо – то е част от стан­дарт­ните проверки по време на изпълнение, които Java прави за вас, та ако ня­кое извикване се прави с нулев манипулатор, Java автоматически изхвърля NullPointerException. Така че горната проверка е винаги излишна.

Има цяла група типове изключения които попадат в тази категория. Те винаги се изхвърлят автоматично от Java и не е необходимо да ги включвате във ва­ши­те спецификации на изключения. Достатъчно удобно те са свързани помежду си чрез единствен базов клас RuntimeException, което е перфектен пример на на­следяване: основава се фамилия от типове които имат нещо общо в по­ве­де­ние­то си. Също никога не е необходимо да правите спецификация в която да спо­менавате че може да се изхвърли RuntimeException, понеже това си се пред­полага. Понеже те индицират бъгове, практически никога не прихващате RuntimeException – това е направено автоматично. Ако непременно трябваше да проверявате за RuntimeExceptionи кодът ви би станал объркан. Въпреки че ти­пично не прихващате RuntimeExceptionи, във ваши собствени пакети може да поискате да изхвърлите RuntimeExceptionи.

Какво се случва ако не прихванете такива изключения? Понеже компилаторът не ви налага да правите спецификации за тях, твърде правдоподобно е че RuntimeException би могъл да се процеди по някакъв начин през вашия main( ) ме­тод без да бъде хванат. За да видите какво става в такъв случай, пробвайте след­ния пример:

//: c09:NeverCaught.java

// Ignoring RuntimeExceptions


public class NeverCaught {

static void f() {

throw new RuntimeException("From f()");

}

static void g() {



f();

}

public static void main(String[] args) {



g();

}

} ///:~



Може вече да сте видели че RuntimeException (или нещо наследено от него) е спе­циален случай, понеже компилеторът не изисква спецификация за тези ти­по­ве.

Изходът е:

java.lang.RuntimeException: From f()

at NeverCaught.f(NeverCaught.java:9)

at NeverCaught.g(NeverCaught.java:12)

at NeverCaught.main(NeverCaught.java:15)

Така че отговорът е следният: Ако RuntimeException се просмуче чрез main( ) без да бъде хванато, вика се printStackTrace( ) за същото изключение и из­пъл­не­нието на про­гра­мата се прекратява.

Помнете че е възможно да се игнорират само RuntimeExceptionите във вашият код, нали за всички други компилаторът грижливо ви заставя да осигурите под­дръж­ка. Основанието е че RuntimeException представя програмни грешки:



  1. Грешка която не можете да хванете (получаване на нулев манипулатор по­да­ден на ваш метод от клиента-програмист, например)

  2. Грешка, която вие, като програмист, трябва да сте проверили в своя код (като ArrayIndexOutOfBoundsException където е трябвало да внимавате за обхвата на индекса да не се надвиши).

Може да се види какви огромни ползи има от този начин на работа с изклю­че­ния­та, те могат да се използват и за тестване.

Интересно е да се отбележи, че не може да се класифицира за поддръжка на из­клю­чения в Java като инструмент с едно приложение. Да, то е проектирано да се справя с онези случаи, когато възникват грешки по време на изпълнение по­ра­ди причини, които не са подвластни на вашия код, но също е важно и за ня­кои типове програмистки грешки, които компилаторът не може да открие.


Създаване на ваши собствени изключения


Не сте огпеничени да използвате само изключнията на Java. Това е важно, по­не­же често трябва да се подработи въпросът с някои грешки, които вашата би­блио­тека може да сътвори, които обаче не са могли да бъдат предсказани ко­га­то се е създавала йерархията на Java.

За да създадете ваш собствен клас за изключение, принудени сте да наследите от съществуващ тип изключение, за предпочитане от това, което е най-близко по значението си до вашето. Наследяването на изключение е доста просто:

//: c09:Inheriting.java

// Inheriting your own exceptions


class MyException extends Exception {

public MyException() {}

public MyException(String msg) {

super(msg);

}

}
public class Inheriting {



public static void f() throws MyException {

System.out.println(

"Throwing MyException from f()");

throw new MyException();

}

public static void g() throws MyException {



System.out.println(

"Throwing MyException from g()");

throw new MyException("Originated in g()");

}

public static void main(String[] args) {



try {

f();


} catch(MyException e) {

e.printStackTrace();

}

try {


g();

} catch(MyException e) {

e.printStackTrace();

}

}



} ///:~

Наследяването се случва при създаването на нов клас:

class MyException extends Exception {

public MyException() {}

public MyException(String msg) {

super(msg);

}

}

Ключовата фраза тук е extends Exception, тоест “това е всичко което е в Exception и още.” Добавеният код е малък – добавени са два конструктора ко­и­то показват как да се създава MyException. Помнете че компилаторът ав­то­ма­тич­но извиква конструктора на базовия клас ако не го извикате явно, както в кон­структора по подразбиране MyException( ). Във втория конструктор кон­струк­торът на базовия кас със String аргумент явно се извиква с ключовата ду­ма super.



Изходът от програмата е:

Throwing MyException from f()

MyException

at Inheriting.f(Inheriting.java:16)

at Inheriting.main(Inheriting.java:24)

Throwing MyException from g()

MyException: Originated in g()

at Inheriting.g(Inheriting.java:20)

at Inheriting.main(Inheriting.java:29)

Може да видите отсъствието на детайлно съобщение в изхвърленото от f( ) MyException.

Процесът на създаване на ваши собствени изключения може да бъде продъл­жен. Може да добавите конструктори и членове:

//: c09:Inheriting2.java

// Inheriting your own exceptions
class MyException2 extends Exception {

public MyException2() {}

public MyException2(String msg) {

super(msg);

}

public MyException2(String msg, int x) {



super(msg);

i = x;


}

public int val() { return i; }

private int i;

}
public class Inheriting2 {

public static void f() throws MyException2 {

System.out.println(

"Throwing MyException2 from f()");

throw new MyException2();

}

public static void g() throws MyException2 {



System.out.println(

"Throwing MyException2 from g()");

throw new MyException2("Originated in g()");

}

public static void h() throws MyException2 {



System.out.println(

"Throwing MyException2 from h()");

throw new MyException2(

"Originated in h()", 47);

}

public static void main(String[] args) {



try {

f();


} catch(MyException2 e) {

e.printStackTrace();

}

try {


g();

} catch(MyException2 e) {

e.printStackTrace();

}

try {



h();

} catch(MyException2 e) {

e.printStackTrace();

System.out.println("e.val() = " + e.val());

}

}

} ///:~



Даннов член i е добавен, заедно с метод който чете стойността му и допъл­ни­те­лен конструктор който я задава. Изходът е:

Throwing MyException2 from f()

MyException2

at Inheriting2.f(Inheriting2.java:22)

at Inheriting2.main(Inheriting2.java:34)

Throwing MyException2 from g()

MyException2: Originated in g()

at Inheriting2.g(Inheriting2.java:26)

at Inheriting2.main(Inheriting2.java:39)

Throwing MyException2 from h()

MyException2: Originated in h()

at Inheriting2.h(Inheriting2.java:30)

at Inheriting2.main(Inheriting2.java:44)

e.val() = 47

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

//: c09:SimpleException.java

class SimpleException extends Exception {

} ///:~


Това се обляга на задължението на компилатора да създаде конструктор по подразбиране (който автоматично вика конструктора на базовия клас). Разбира се, в този случай нямате SimpleException(String) конструктор, но на практика той не се и използва много.



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




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

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