• Nie Znaleziono Wyników

Programowanie obiektowe

N/A
N/A
Protected

Academic year: 2022

Share "Programowanie obiektowe"

Copied!
23
0
0

Pełen tekst

(1)

Programowanie obiektowe

Wykład 8: Obsługa wyjątków

dr inż. Marcin Luckner mluckner@mini.pw.edu.pl

Wydział Matematyki i Nauk Informacyjnych

Wersja 1.4 4 marca 2021

(2)

Projekt „NERW 2 PW. Nauka – Edukacja – Rozwój – Współpraca” współfinansowany jest ze środków Unii Europejskiej

w ramach Europejskiego Funduszu Społecznego.

Zadanie 10 pn. „Modyfikacja programów studiów na kierunkach prowadzonych przez Wydział Matematyki i Nauk Informacyjnych”,

realizowane w ramach projektu „NERW 2 PW. Nauka – Edukacja – Rozwój – Współpraca”, współfinansowanego jest ze środków Unii Europejskiej w ramach Europejskiego Funduszu Społecznego.

(3)

Przerwanie działania aplikacji

Nawet najlepiej zaprojektowany algorytm realizuje tylko rutynowe działania.

W przypadku nieprzewidzianych zdarzeń algorytm może nie mieć możliwości ich poprawnej realizacji.

Przyczynami problemów mogą być:

Niepoprawne dane wejściowe

Przerwane połączenie

Błędna inicjalizacja metody

W przypadku wystąpienia problemu aplikacja powinna zachować się w sposób przyjazny dla użytkownika.

Powiadomić wyczerpująco o błędzie.

Zapisać dotychczasową pracę.

Zakończyć poprawnie działanie elementów programu, których przerwanie mogłoby prowadzić do dalszych problemów.

Java pozwala radzić sobie z takimi sytuacjami dzięki obsłudze wyjątków.

(4)

Informowanie o błędnym działaniu metody

Jeżeli działanie funkcji będzie błędne i błąd da się wykryć to mamy kilka możliwości postępowania.

Funkcja może zwrócić określoną wartość ze swojej przeciwdziedziny.

Metoda wywołująca może nie rozpoznać komunikatu błędu

Możemy nie mieć dostępnej wartości do przypisania błędu

Funkcja może zwrócić wartośćnull.

Metoda wywołująca może próbować potraktować wynik jako pełnoprawny obiekt.

Metoda wywołująca musi kontrolować poprawność zwracanego argumentu.

Funkcja może wygenerować wyjątek.

Musi istnieć mechanizm obsługi wyjątków.

(5)

Obsługa wyjątków

Rysunek 1:Stos wywołań metod i wsteczne przekazywanie wyjątku.

Po wystąpieniu wyjątku przerywanie jest działanie metod, które nie zapewniają obsługi wyjątku.

Jeżeli przerwanie dojdzie do metody main() aplikacja zostanie zatrzymana.

(6)

Typy wyjątków

Rysunek 2:Hierarchia wyjątków

Wszystkie wyjątki należą do klasy Throwable.

Wyjątki z klasy Error odpowiadają poważnym błędom wewnętrznym i nie można nic na nie poradzić.

Wyjątki z klasy

RuntimeException są wynikiem błędnego programowania i da się je wyeliminować podczas pisania kodu.

Pozostałe wyjątki powinny być obsłużone.

(7)

Wyjątki niekontrolowane

Wyjątki Error i RuntimeException są wyjątkami niekontrolowanymi.

Oznacza to, że nie możemy przewidzieć ich wystąpienia lub nie powinniśmy zakładać, że mogą wystąpić.

Nie możemy też ostrzec użytkowników, w sposób formalny, że mogą wystąpić.

Złota zasada

Jeśli wystąpił wyjątek RuntimeException, znaczy, że popełniłeś błąd jako programista!

(8)

Deklarowanie wyjątków kontrolowanych

Możliwość wystąpienia wyjątków kontrolowanych jest sygnalizowana w deklaracji metody.

Deklaracja następuje poprzez słowo kluczowe throwsi wymienienie wyjątków, które mogą wystąpić

1 p u b l i c I m a g e l o a d I m a g e ( S t r i n g s ) t h r o w s F i l e N o t F o u n d E x c e p t i o n , E O F E x c e p t i o n

Jeżeli funkcja deklaruje wyjątek kontrolowany to funkcja wykonująca musi przekazać go dalej lub obsłużyć.

(9)

Przekazywanie wyjątków

Jeżeli sami nie potrafimy obsłużyć wyjątku to powinniśmy przekazać jego obsługę funkcji wywołującej poprzez dodanie klauzulithrows.

Tworzy to jednak pewne problemy.

Załóżmy, że modyfikujemy istniejącą metodę i wymaga to dodania klauzulithrows.

Teraz wszystkie funkcje wywołujące naszą metodę muszą albo przechwycić wyjątek, albo zadeklarować kontrolowany wyjątek.

Może to skutkować masową refaktoryzacją kodu.

(10)

Przechwytywanie wyjątków

Przechwytywanie wyjątku opiera się na zastosowaniu trzech bloków.

Przechwycenie wyjątku

1 try {

2 r e a d D a t a ( f i l e N a m e ) ;

3 }

4 c a t c h ( E O F E x c e p t i o n e ) { 5 e . p r i n t S t a c k T r a c e () ;

6 }

7 f i n a l l y {

8 c l o s e F i l e ( f i l e N a m e ) ;

9 }

try deklaracja bloku kodu obserwowanego pod kątem generowania wyjątków.

catch definicja sposobu postępowania z wyjątkami.

finally definicja operacji. które muszą być wykonane niezależnie od wystąpienia wyjątku.

(11)

Blok try

Blok tryokreśla fragment kodu, który może wygenerować wyjątek.

Każda metoda z klauzulą throwsmusi być umieszczona w bloku try(lub wyjątek zostanie przekazany)

(12)

Blok catch

Blok catchopisuje zachowanie po wykryciu konkretnego wyjątku.

Możemy obsłużyć wiele wyjątków z jednego bloku try.

Zestaw bloków catch

1 try {

2 r e a d D a t a ( f i l e N a m e ) ; 3 }

4 c a t c h ( E O F E x c e p t i o n e ) { 5 e . p r i n t S t a c k T r a c e () ; 6 }

7 c a t c h ( F i l e N o t F o u n d E x c e p t i o n e | U n k n o w n H o s t E x c e p t i o n e ) { 8 e . p r i n t S t a c k T r a c e () ; 9 }

Bloki mogą być definiowane oddzielnie dla różnych wyjątków lub grupować wyjątki.

(13)

Blok finally

Blok finallyzawiera fragment kodu, który zostanie wykonany niezależnie od tego czy wystąpił wyjątek.

Zazwyczaj służy do zamknięcia otwartych połączeń z źródłami danych.

Może być źródłem nowych wyjątków.

Blokfinally generujący wyjątek

1 try {

2 o p e n F i l e ( f i l e N a m e ) ; 3 r e a d D a t a ( f i l e N a m e ) ;

4 }

5 c a t c h ( F i l e N o t F o u n d E x c e p t i o n e ) { 6 e . p r i n t S t a c k T r a c e () ;

7 }

8 f i n a l l y {

9 c l o s e F i l e ( f i l e N a m e ) ;

10 }

Próba zamknięcia pliku przez metodę closeFile spowoduje wyjątek.

(14)

Zagnieżdżenie bloków

Problem kodu generującego wyjątki w blokufinally można rozwiązać zagnieżdżając bloki

Blokfinally generujący wyjątek

1 p u b l i c s t a t i c v o i d m a i n ( S t r i n g [] a r g s ) {

2 try {

3 if( a r g s . l e n g t h > 0) { // Nie z a w s z e p o t r z e b u j e m y w y j a t k o w

4 S t r i n g f i l e N a m e = a r g s [ 0 ] ; 5 o p e n F i l e ( f i l e N a m e ) ;

6 try {

7 r e a d D a t a ( f i l e N a m e ) ;

8 }

9 c a t c h ( E O F E x c e p t i o n e ) {

10 e . p r i n t S t a c k T r a c e () ;

11 }

12 f i n a l l y {

13 c l o s e F i l e ( f i l e N a m e ) ;

14 }

15 }

16 }

17 c a t c h ( F i l e N o t F o u n d E x c e p t i o n e ) { 18 e . p r i n t S t a c k T r a c e () ;

19 }

20 }

Zagnieżdżanie dodatkowo porządkuje funkcjonalność kodu.

(15)

Blok try z zasobami

Innym rozwiązaniem jest stosowanie blokutry z zasobami.

Rozwiązanie można stosować do obiektów implementujących interfejs AutoCloseable i nadpisujących jego metodę close.

Przepisanie pliku

1 try ( S c a n n e r in = new S c a n n e r (new

F i l e I n p u t S t r e a m (" / usr / s h a r e / d i c t / w o r d s ") , " UTF -8 ") , 2 P r i n t W r i t e r out = new P r i n t W r i t e r (" out . txt ") )

3 {

4 w h i l e ( in . h a s N e x t () )

5 out . p r i n t l n ( in . n e x t () . t o U p p e r C a s e () ) ;

6 }

Niezależnie od sposobu zakończenia wykonywania bloku zasoby in i out zostaną zamknięte.

(16)

Wywoływanie wyjątków

Wyjątek wywołujemy używając słowa kluczowego throw.

W przypadku konieczności wywołania wyjątku zastanawiamy się jakiej klasy wyjątku użyć i rzucamy jej instancję.

Przykładowo, jeżeli otrzymaliśmy informację o końcu pliku, a logika wskazuje, że nie powinien on nastąpić to rzucamy wyjątek końca pliku.

throw new EOFException();

Do wyjątku możemy dodać informację opisującą okoliczności jego wystąpienia

1 S t r i n g g r i p e = " W p l i k u " + n a z w a P l i k u + " , n a s t a p i l n i e s p o d z i e w a n y k o n i e c p l i k u w l i n i : " + n u m e r L i n i i ; 2 t h r o w new E O F E x c e p t i o n ( g r i p e ) ;

Możemy też utworzyć własną klasę wyjątku.

(17)

Tworzenie własnej klasy wyjątków

Klasę wyjątku tworzymy nadpisując klasę Exception lub jedną z jej podklas.

Klasa zawiera

konstruktor bezparametryczny,

konstruktor przekazujący tekst wiadomości

metodę zwracającą wiadomość getMessage

Klasa wyjatku

1 c l a s s F i l e F o r m a t E x c e p t i o n e x t e n d s I O E x c e p t i o n { 2 p u b l i c F i l e F o r m a t E x c e p t i o n () {}

3 p u b l i c F i l e F o r m a t E x c e p t i o n ( S t r i n g g r i p e )

4 {

5 s u p e r( g r i p e ) ;

6 }

7 }

Już sam fakt wyrzucenia wyspecjalizowanego wyjątku niesie dodatkową informację, której nie mamy przy wyrzuceniu standardowego wyjątku.

(18)

Łańcuchy wyjątków

Może być wskazane wyrzucenie wyspecjalizowanego wyjątku po przechwyceniu ogólnego wyjątku

1 try{

2 r e a d F i l e ( f i l e N a m e ) ;

3 }

4 c a t c h ( I O E x c e p t i o n e ) {

5 t h r o w new F i l e F o r m a t E x c e p t i o n (" B l a d f o r m a t u p l i k u :

" + e . g e t M e s s a g e () ) ;

6 }

Aby nie tracić informacji o pierwotnym wyjątku można utworzyć łańcuch wyjątków

1 c a t c h ( I O E x c e p t i o n e ) {

2 T h r o w a b l e se = new F i l e F o r m a t E x c e p t i o n (" B l a d f o r m a t u p l i k u : ") ;

3 se . i n i t C a u s e ( e ) ;

4 t h r o w se ;

5 }

Pierwotny wyjątek da się odczytać przy pomocy metody getCause klasy Throwable.

(19)

Testowanie kodu

Możliwość rzucania błędów może być wykorzystana do testowania kodu.

Nie stosuje się do tego wyjątków, bo spowolniałyby pracę aplikacji w normalnych warunkach.

Zamiast tego stosujemy mechanizm asercji.

(20)

Asercje

W Javie dostępne jest słowo kluczowe assert, które sprawdza prawdziwość zadanego warunku.

assert warunek;

assert warunek:zwracane_wyrazenie;

Jeżeli warunek jest spełniony wykonywanie kodu jest kontynuowane.

Jeżeli warunek nie jest spełniony wyrzucany jest błąd AssertionError nadpisujący klasę Error.

(21)

Wyliczanie pierwiastka

Spróbujmy wyliczyć pierwiastek kwadratowy z podanej liczby.

1 d o u b l e x = e x t e r n a l O b j e c t . g e t P o s i t i v e X () ; 2 d o u b l e y = M a t h . s q r t ( x ) ;

Podczas kodowania, istnieje niebezpieczeństwo, że nie dopilnowano, aby metoda getPositiveX dostarczała nieujemny wynik.

Zabezpieczamy się przed tym stosując asercję

1 a s s e r t x > = 0 :" p i e r w i a s t e k z " + x ; 2 d o u b l e y = M a t h . s q r t ( x ) ;

Wynik

Exception in thread "main" java.lang.AssertionError: pierwiastek z -1.0 at pl.edu.pw.mini.mluckner.op.lecture08.AssertionTest.main(AssertionTest.java:6)

(22)

Włączanie asercji

Przy standardowych ustawieniach asercje są wyłączone.

Uruchamiamy je poprzez użycie opcji -enableassertions lub -ea w parametrach maszyny wirtualnej.

Wywołanie

java -enableassertions MyApp

Asercji używa się tylko podczas testowania oprogramowania, do sprawdzenia czy metody poprawnie przesyłają parametry.

Nie trzeba ich usuwać z kodów w upublicznionej wersji oprogramowania, aplikacje są po prostu uruchamiane bez ich aktywacji.

(23)

Bibliografia

Cytaty

Powiązane dokumenty

Funkcja PokazDaneDokumentu() została natomiast stworzona do pracy z obiektami CDocument, zatem wykorzystuje jedynie informacje zawarte w klasie bazowej. Nie przeszkadza to jednak

Za pomocą klas programista stara się opisać obiekty, ich właściwości, zbudować konstrukcje, interfejs, dzięki któremu będzie można wydawać polecenia realizowane potem

Każda podprzestrzeń skończeniewymiarowa jest podmo- dułem skończenie generowanym.. (12) Niech A będzie addytywną

public void actionPerformed(ActionEvent arg0) {  setTitle("Anonimowa klasa wewnetrzna");  . } }

Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW) 80/116 public class MenuWindow extends JFrame {.

strumieniowych związanych z plikami podaliśmy jako argument nazwę pliku → 4 klasy strumieni abstrakcyjnych. ● można także utworzyć strumień plikowy podając jako

protected void done() - wywoływana po zakończeniu zadania, wykonywana w EDT, można w niej przeprowadzić „sprzątanie” i zaprezentować w GUI główny rezultat wykonywanego

– Ustalamy rodzaj bazy danych, w jakiej chcemy ją zapisać. Łatwe, → Łatwe, relacyjna... – Ustalamy jakiego DBMS będziemy używać.