Obsługa błędów
Transkrypt
Obsługa błędów
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 • An exception always "abruptly terminates" a statement or sequence of statements in 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(); } }