Obsługa błędów
Rakieta Ariane 5 spadła 40 sekund po starcie. Straty 0,5 miliarda dolarów.
Przyczyna: wyjątek (exception) rzucony przez kod napisany pierwotnie dla Ariane 4 . Feralna procedura była
niepotrzebna w trakcie lotu. Wyniki obliczeń przekroczyły zakres typu short int dla większej rakiety (5) wywołując wyjątek overflow. Nie przewidziano procedury obsługi tego
przypadku poniewaŜ nie „było szans” jego wystąpienia. W Ariane 5 spowodowało to jednak zakończenie programu. Po
załamaniu programu sterującego zostały uruchomione komputery zastępcze, ale wszystkie wdraŜały ten sam
program ...
Obsługa błędów
• Często niedoceniana i „spychana” na dalszy plan (etap) realizacji projektu
• W obsłudze błędów trudno wykazać się kreatywnością, polotem etc.
• Kod związany z obsługą błędów nie wnosi nowych elementów do programu
• Powinna być rutynowa, metodyczna...
(czyli nudna)
Konwencje obsługi błędów
Stosowano róŜne schematy obsługi błędów: Funkcje zwracają kod błędu (Visa Library)
Ustawiają specjalną flagę (iberr – NI GPIB library)
Takie rozwiązania prowadzą do kodu, w którym funkcje podstawowe i obsługa błędów są „przemieszane” i tym samym słabo czytelne, a ponadto formalnie nie zmuszają programisty do reakcji na te błędy w myśl zasady; „błędy przytrafiają się innym, nie mnie”
Obecnie stosowana koncepcja obsługi wyjątków wywodzi się z rozwiązań stosowanych w systemach operacyjnych w latach „60”, „on error goto” Basica i przez języki Ada oraz C++ trafiła do Javy
Exception handling
• "Anything that can go wrong will go wrong."
• An exception handler can return to the instruction that generated the problem This is a dangerous facility to give to an application program
• A A n exception always "abruptly terminates" n exception always "abruptly terminates"
a statement or sequence of statements in
a statement or sequence of statements in
a block and exits to an outer block of code
a block and exits to an outer block of code
Definicja
Wyjątek (Exception) to zdarzenie występujące w trakcie wykonania
programu, które przerywa normalny tok wykonywania instrukcji.
• W miejscu wystąpienia problemu nie wiadomo co zrobić, nie moŜna zatem
kontynuować działania naleŜy je przerwać i przekazać decyzję co dalej robić na
wyŜszy poziom
Przyczyny
• Wiele źródeł błędów moŜe powodować powstanie
wyjątków poczynając od uszkodzeń sprzętowych takich jak awaria dysku, do prostych błędów programowych jak próba odwołania do indeksu tablicy wykraczająca poza jej rozmiar. Jeśli taki błąd powstanie wewnątrz metody kreowany jest obiekt wyjątku i przekazywany do systemu wykonania. Obiekt ten zawiera informację o swoim typie i stanie programu, kiedy powstał błąd. System wykonania jest odpowiedzialny za znalezienie kodu obsługi tego
błędu. W Javie tworzenie obiektu wyjątku i przekazanie go do systemu wykonania określane jest jako rzucanie wyjątku (throwing an exception).
Przechwytywanie wyjątków
• Sekwencja wywołania metod przechowywana jest na stosie. System wykonania rozpoczyna poszukiwanie metody, która posiada
odpowiednią procedurę obsługi wyjątku
(exception handler) poczynając od metody w której powstał wyjątek w kolejności odwrotnej do sekwencji wywoływania metod. Odpowiednia procedura to taka, która obsługuję wyjątek
danego typu. O takiej procedurze mówi się, Ŝe
„przechwyciła” wyjątek. Jeśli system wykonania nie znajdzie odpowiedniej procedury obsługi
program kończy działanie.
To dla mnie sytuacja wyjątkowa
• NajpowaŜniejszą zaletą takiego podejścia jest moŜliwość separacji kodu realizującego główne funkcje programu z obsługą potencjalnych
błędów.
• Sytuacja wyjątkowa to taka, w której nie
moŜemy kontynuować programu poniewaŜ nie mamy w bieŜącym kontekście wystarczających danych i jedyne co moŜemy zrobić to przerwać wykonanie tego kontekstu i przekazać
sterowanie na zewnątrz do procedury obsługi (na
wyŜszy poziom).
Rzucanie wyjątku
SomeType metoda(Object t) { if(t == null)
throw new NullPointerException();
// ...
}
Uwagi:
1. Mamy całą hierarchię klas „wyjątkowych”, której
wierzchołkiem jest klasa Throwable i możemy definiować
„własne” wyjątki
2. throw new NullPointerException("t = null"); // 2gi konstruktor
3. metoda „zwraca” obiekt wyjątku! A nie obiekt SomeType
Instrukcja throw
• Instrukcja throw jest rodzajem skoku, który przekazuje sterowanie do odpowiedniej części catch w bieŜącej metodzie bądź metodzie
wywołującej ją ...
• Metoda, w czasie wykonania której moŜe dojść do sytuacji wyjątkowej (błędu) deklaruje to
przez uŜycie throws
void f() throws TooBig, TooSmall, DivZero { //...
Kompilator, jeśli uŜyjemy metody deklarującej rzucanie wyjątku forsuje nas do jego obsługi
Uwaga:Nie dotyczy to RuntimeException
Region „chroniony”
try {
// Code that might generate exceptions } catch(Type1 id1) {
// Handle exceptions of Type1 } catch(Type2 id2) {
// Handle exceptions of Type2
} catch(Type3 id3) { // Handle exceptions of Type3 }
// etc...
Uwaga: Sterowanie jest przekazywane do pierwszej
procedury obsługi wyjątku zgodnej z typem i uznaje się że wyjątek został obsłużony!
Sprzątanie - finally
try {
// The guarded region: Dangerous activities // that might throw A, B, or C
} catch(A a1) {
// Handler for situation A } catch(B b1) {
// Handler for situation B } catch(C c1) {
// Handler for situation C } finally {
// Activities that happen every time }
MoŜna „oszukać” kompilator?
• Jeśli kod wewnątrz metody moŜe spowodować wyjątek, a nie dostarczymy procedury jego obsługi zostaniemy
„zdyscyplinowani” przez kompilator
try {
// Code that might generate exceptions } catch(Type1 id1) {
// Handle exceptions of Type1 }
lub moŜemy przekazać obsługę na wyŜszy poziom SomeType metoda () throws Type1 {
// Code that might generate exceptions }
MoŜna ale ...
SomeType metoda () throws Type1 {
// Code that does not generate any exceptions
// ale będzie, tylko Ŝe teraz skupiamy się na głównym //zadaniu metody
// rozwiązujemy zadanie jak wszystko jest ok później dołączymy kod typu:
// „if something will go wrong”
}
Uwaga: Podobne podejście zastosujemy w klasach abstrakcyjnych i w interfejsach
Termination vs resumption
In termination you assume that the error is so critical that there’s no way to get back to where the
exception occurred. Whoever threw the exception decided that there was no way to salvage the
situation, and they don’t want to come back.
W Javie (podobnie jak w C++) obowiązuje zasada, Ŝe nie ma moŜliwości (sensu) ponowienia wykonania kodu, który rzucił wyjątek. Jeśli uwaŜasz, Ŝe procedura obsługi wyjątku moŜe coś naprawić, co umoŜliwi kontynuowanie wykonania metody nie rzucaj wyjątku ale wywołaj procedurę naprawczą!
MoŜna teŜ umieścić try-catch blok w pętli...
Własne klasy wyjątków
class MyException2 extends Exception { private int x;
public MyException2() {}
public MyException2(String msg) { super(msg); } public MyException2(String msg, int x) {
super(msg); this.x = x; } public int val() { return x; }
public String getMessage() { return "Detail Message: "+ x + "
"+ super.getMessage();
} }