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



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

Финализиране с finally


Често има парче код, което бихте искали да се изпълни в try блока, независимо да­ли има или не изключение. То обикновено е свързано с операции различни от ос­во­бождаването на рачет (понеже за последното се грижи боклучарят). За да се постигне това се използва клаузата finally4 в края на всички обработчици на из­ключения. Така пълната картина на кода за обработка на изключения е след­на­та:

try {
// Охраняваният регион:
// Опасни неща които могат да изхвърлят A, B или C
} catch (A a1) {
// Манипулатор A
} catch (B b1) {
// Манипулатор B
} catch (C c1) {
// Манипулатор C
} finally {
// Парченцето код, което трябва да се изпълни винаги
}

За да се демонстрира че finally винаги се пуска, опитваме следната програма:

//: c09:FinallyWorks.java

// The finally clause is always executed


public class FinallyWorks {

static int count = 0;

public static void main(String[] args) {

while(true) {

try {

// post-increment is zero first time:



if(count++ == 0)

throw new Exception();

System.out.println("No exception");

} catch(Exception e) {

System.out.println("Exception thrown");

} finally {

System.out.println("in finally clause");

if(count == 2) break; // out of "while"

}

}

}



} ///:~

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

Изходът е:

Exception thrown

in finally clause

No exception

in finally clause

Било или не изхвърлено изключение, клаузата на finally винаги се изпълнява.


За какво е finally?


В език без боклукосъбиране и без автоматично извикване на деструктори,5 finally е важна, понеже дава възможност на програмиста да гарантира осво­бож­да­ването на паметта без значение какво се е случило в try блока. Но Java има съ­биране на боклука, така че освобождаването на паметта практически никога не е проблем. Също, няма деструктори за извикване. Кога има нужда от finally в Java?

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

//: c09:OnOffSwitch.java

// Why use finally?
class Switch {

boolean state = false;

boolean read() { return state; }

void on() { state = true; }

void off() { state = false; }

}
public class OnOffSwitch {

static Switch sw = new Switch();

public static void main(String[] args) {

try {

sw.on();


// Code that can throw exceptions...

sw.off();

} catch(NullPointerException e) {

System.out.println("NullPointerException");

sw.off();

} catch(IllegalArgumentException e) {

System.out.println("IOException");

sw.off();

}

}

} ///:~



Целта тук е ключът да бъде изключен когато main( ) завърши, така че sw.off( ) се слага на края на трай блока на края на обработчика. Възможно е обаче да е из­хвърлено изключение което да не е прихванато точно тука, така че sw.off( ) ще се пропусне. С finally може да сложите завършващия код на трай блока в само едно място:

//: c09:WithFinally.java

// Finally Guarantees cleanup
class Switch2 {

boolean state = false;

boolean read() { return state; }

void on() { state = true; }

void off() { state = false; }

}
public class WithFinally {

static Switch2 sw = new Switch2();

public static void main(String[] args) {

try {

sw.on();


// Code that can throw exceptions...

} catch(NullPointerException e) {

System.out.println("NullPointerException");

} catch(IllegalArgumentException e) {

System.out.println("IOException");

} finally {

sw.off();

}

}



} ///:~

Тук sw.off( ) е преместено на въпросното място, където гарантирано ще се изпълни без значение какво ще се случи.

Даже и в случаите когато изключението не е хванато в текущото множество на catch клаузи, finally ще се изпълни преди механизмът за поддръжка на из­клю­че­нията да продължи търсенето си на обработчик в следващия по-широк кон­текст:

//: c09:AlwaysFinally.java

// Finally is always executed
class Ex extends Exception {}
public class AlwaysFinally {

public static void main(String[] args) {

System.out.println(

"Entering first try block");

try {

System.out.println(



"Entering second try block");

try {


throw new Ex();

} finally {

System.out.println(

"finally in 2nd try block");

}

} catch(Ex e) {



System.out.println(

"Caught Ex in first try block");

} finally {

System.out.println(

"finally in 1st try block");

}

}



} ///:~

Изходът от тази програма показва какво се случва:

Entering first try block

Entering second try block

finally in 2nd try block

Caught Ex in first try block

finally in 1st try block

Операторът finally ще се изпълни в ситуации където има break и continue опе­ра­тори. Забележете че заедно с етикетирания break и continue, finally ели­ми­ни­ра нуждата от goto оператор в Java.


Капан: загубеното изключение


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

//: c09:LostMessage.java

// How an exception can be lost
class VeryImportantException extends Exception {

public String toString() {

return "A very important exception!";

}

}


class HoHumException extends Exception {

public String toString() {

return "A trivial exception";

}

}


public class LostMessage {

void f() throws VeryImportantException {

throw new VeryImportantException();

}

void dispose() throws HoHumException {



throw new HoHumException();

}

public static void main(String[] args)



throws Exception {

LostMessage lm = new LostMessage();

try {

lm.f();


} finally {

lm.dispose();

}

}

} ///:~



Изходът е:

A trivial exception

at LostMessage.dispose(LostMessage.java:21)

at LostMessage.main(LostMessage.java:29)

Може да се види, че няма следа от VeryImportantException, което просто е за­ме­стено от HoHumException във finally клаузата. Това е достатъчно сериозен ка­пан, понеже изключение може да бъде напълно изгубено, също и в много по-за­сукана и трудна за проследяване ситуация отколкото горната. За контраст, C++ третира ситуацията в която се изхвърля едно изключение преди да е при­клю­чила обработката на друго като ужасяваща програмна грешка. Може би ня­коя бъзеща версия на Java ще оправи проблема. (Горните резултати се произ­ве­до­ха с Java 1.1.)




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




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

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