SlideShare a Scribd company logo
1 of 31
Download to read offline
IDZ DO
         PRZYK£ADOWY ROZDZIA£

                           SPIS TRE CI   Praktyczny kurs Java
                                         Autor: Marcin Lis
           KATALOG KSI¥¯EK               ISBN: 83-7361-395-1
                                         Format: B5, stron: 384
                      KATALOG ONLINE

       ZAMÓW DRUKOWANY KATALOG


              TWÓJ KOSZYK
                                                             Poznaj tajniki najpopularniejszego
                    DODAJ DO KOSZYKA                      jêzyka programowania w erze Internetu
                                         Chyba wszyscy u¿ytkownicy internetu spotkali siê z Jav¹, czêsto nawet o tym nie
                                         wiedz¹c. W ci¹gu ostatnich 10 lat zyska³a ona ogromn¹ popularno æ, szczególnie
         CENNIK I INFORMACJE             w ród programistów aplikacji sieciowych. Jednak¿e kojarzenie jej z jêzykiem
                                         przeznaczonym wy³¹cznie do tworzenia takich programów jest du¿ym b³êdem.
                   ZAMÓW INFORMACJE      Java to w pe³ni funkcjonalny i doskonale dopracowany jêzyk programowania,
                     O NOWO CIACH        nadaj¹cy siê do tworzenia ró¿nych aplikacji, a nie tylko apletów dzia³aj¹cych
                                         na stronach internetowych.
                       ZAMÓW CENNIK      W Javie pisane s¹ gry sieciowe, systemy bankowo ci elektronicznej, pakiety
                                         wspomagaj¹ce sprzeda¿ i obs³ugê klienta, a nawet aplikacje dzia³aj¹ce w telefonach
                                         komórkowych i komputerach przeno nych. Podstawow¹ zalet¹ jêzyka Java jest
                 CZYTELNIA               przeno no æ kodu -- raz napisany program mo¿na uruchomiæ na ka¿dym urz¹dzeniu,
                                         na którym zainstalowane jest odpowiednie rodowisko uruchomieniowe, zwane JRE.
          FRAGMENTY KSI¥¯EK ONLINE
                                         Ksi¹¿ka „Praktyczny kurs Java” przeznaczona jest dla osób rozpoczynaj¹cych swoj¹
                                         przygodê z programowaniem w tym jêzyku. Opisuje podstawy jêzyka, zasady
                                         programowania obiektowego i tworzenia w³asnych apletów i aplikacji.
                                         Czytaj¹c kolejne rozdzia³y, dowiesz siê:
                                            • Jakie typy danych wykorzystywane s¹ w Javie
                                            • Jak deklarowaæ zmienne i wyprowadzaæ ich warto ci na ekran
                                            • W jaki sposób sterowaæ przebiegiem wykonywania programu
                                            • Jakie zasady rz¹dz¹ programowaniem obiektowym
                                            • Czym s¹ klasy, obiekty, argumenty i metody
                                            • Co to s¹ wyj¹tki i jak je obs³ugiwaæ w programie
                                            • Jak wykorzystaæ zaawansowane techniki programowania obiektowego
Wydawnictwo Helion
                                              w swoich aplikacjach
ul. Chopina 6
                                            • W jaki sposób uzyskiwaæ dostêp do systemu plików z poziomu swojej aplikacji
44-100 Gliwice
tel. (32)230-98-63                          • Jak tworzyæ aplety i samodzielne aplikacje
e-mail: helion@helion.pl                 Zapoznaj siê z podstawami programowania w Javie i naucz siê zasad programowania
                                         obiektowego, a tak¿e dowiedz siê, czym s¹ wyj¹tki w Javie i stwórz w³asne aplety
                                         i aplikacje.
Spis treści
                Wstęp ............................................................................................... 5
Rozdział 1. Podstawy .......................................................................................... 7
                     Lekcja 1. Struktura programu, kompilacja i wykonanie...............................................7
                     Lekcja 2. Podstawy obiektowości i typy danych ..........................................................9
                     Lekcja 3. Komentarze .................................................................................................12
Rozdział 2. Instrukcje języka ............................................................................. 17
                Zmienne.............................................................................................................................17
                    Lekcja 4. Deklaracje i przypisania..............................................................................18
                    Lekcja 5. Wyprowadzanie danych na ekran ...............................................................21
                    Lekcja 6. Operacje na zmiennych...............................................................................27
                Instrukcje sterujące............................................................................................................39
                    Lekcja 7. Instrukcja warunkowa if...else ....................................................................39
                    Lekcja 8. Instrukcja switch i operator warunkowy.....................................................45
                    Lekcja 9. Pętle.............................................................................................................49
                    Lekcja 10. Instrukcje break i continue........................................................................56
                Tablice...............................................................................................................................63
                    Lekcja 11. Podstawowe operacje na tablicach............................................................64
                    Lekcja 12. Tablice wielowymiarowe..........................................................................68
Rozdział 3. Programowanie obiektowe ............................................................... 79
                Podstawy ...........................................................................................................................79
                   Lekcja 13. Klasy, pola i metody .................................................................................80
                   Lekcja 14. Argumenty i przecią anie metod ..............................................................87
                   Lekcja 15. Konstruktory .............................................................................................98
                Dziedziczenie ..................................................................................................................110
                   Lekcja 16. Klasy potomne ........................................................................................110
                   Lekcja 17. Specyfikatory dostępu i pakiety..............................................................118
                   Lekcja 18. Przesłanianie metod i składowe statyczne ..............................................132
                   Lekcja 19. Klasy i składowe i finalne.......................................................................145
Rozdział 4. Wyjątki ......................................................................................... 153
                     Lekcja 20. Blok try...catch ........................................................................................153
                     Lekcja 21. Wyjątki to obiekty...................................................................................162
                     Lekcja 22. Własne wyjątki........................................................................................169
4                                                                                                                   Praktyczny kurs Java


Rozdział 5. Programowanie obiektowe II .......................................................... 181
                Polimorfizm.....................................................................................................................181
                    Lekcja 23. Konwersje typów i rzutowanie obiektów................................................181
                    Lekcja 24. Późne wiązanie i wywoływanie metod klas pochodnych .......................190
                    Lekcja 25. Konstruktory oraz klasy abstrakcyjne.....................................................199
                Interfejsy..........................................................................................................................209
                    Lekcja 26. Tworzenie interfejsów.............................................................................209
                    Lekcja 27. Wiele interfejsów ....................................................................................216
                Klasy wewnętrzne ...........................................................................................................226
                    Lekcja 28. Klasa w klasie .........................................................................................226
                    Lekcja 29. Rodzaje klas wewnętrznych i dziedziczenie ...........................................235
                    Lekcja 30. Klasy anonimowe i zagnie d one...........................................................244
Rozdział 6. System wejścia-wyjścia.................................................................. 253
                     Lekcja 31. Standardowe wejście...............................................................................253
                     Lekcja 32. Standardowe wejście i wyjście ...............................................................263
                     Lekcja 33. System plików.........................................................................................273
                     Lekcja 34. Operacje na plikach.................................................................................283
Rozdział 7. Aplikacje i aplety ........................................................................... 301
                Aplety ..............................................................................................................................301
                   Lekcja 35. Podstawy apletów ...................................................................................301
                   Lekcja 36. Czcionki i kolory.....................................................................................310
                   Lekcja 37. Grafika ....................................................................................................319
                   Lekcja 38. Dźwięki i obsługa myszy ........................................................................330
                Aplikacje .........................................................................................................................340
                   Lekcja 39. Tworzenie aplikacji.................................................................................340
                   Lekcja 40. Komponenty............................................................................................359
                Skorowidz...................................................................................... 375
Rozdział 4.
Wyjątki
     Praktycznie w ka dym większym programie powstają jakieś błędy. Powodów jest
     bardzo wiele, mo e być to skutek niefrasobliwości programisty, zało enia, e wpro-
     wadzone dane są zawsze poprawne, niedokładnej specyfikacji poszczególnych modu-
     łów aplikacji, u ycia niesprawdzonych bibliotek czy nawet zwykłego zapomnienia
     o zainicjowaniu jednej tylko zmiennej. Na szczęście w Javie, tak jak i w większości
     współczesnych obiektowych języków programowania, istnieje mechanizm tzw. wyjąt-
     ków, który pozwala na przechwytywanie błędów. Ta właśnie tematyka zostanie przed-
     stawiona w kolejnych trzech lekcjach.


Lekcja 20. Blok try...catch
     Lekcja 20. jest poświęcona wprowadzeniu w tematykę wyjątków. Zobaczymy, jakie
     są sposoby zapobiegania powstawaniu niektórych typów błędów w programach,
     dowiemy się, jak stosować przechwytujący błędy blok instrukcji VT[ECVEJ. Po-
     znamy bli ej wyjątek o nieco egzotycznej dla początkujących programistów nazwie
     #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP, dzięki któremu będziemy mogli uniknąć błędów
     związanych z przekroczeniem dopuszczalnego zakresu indeksów tablic.

Sprawdzanie poprawności danych
     Powróćmy na chwilę do rozdziału 2. i lekcji 11. Znajdował się tam przykład, w którym
     następowało odwołanie do nieistniejącego elementu tablicy (listing 2.38). Występowała
     tam sekwencja instrukcji:
       KPV VCD=?  PGY KPV=?
       VCD=?  

     Doświadczony programista od razu zauwa y, e instrukcje te są błędne, jako e zade-
     klarowana została tablica dziesięcioelementowa, więc — poniewa indeksowanie
     tablicy zaczyna się od zera — ostatni element tablicy ma indeks . Tak więc instrukcja
     VCD=?   powoduje próbę odwołania się do nieistniejącego jedenastego elementu
     tablicy. Ten błąd jest jednak stosunkowo prosty do wychwycenia, nawet gdyby pomiędzy
     deklaracją tablicy a nieprawidłowym odwołaniem były umieszczone inne instrukcje.
154                                                                      Praktyczny kurs Java


         Du o więcej kłopotów mogłyby nam sprawić sytuacja, gdyby np. tablica była deklaro-
         wana w jednej klasie, a odwołanie do niej następowało w innej klasie. Taka przykładowa
         sytuacja została przedstawiona na listingu 4.1.
Listing 4.1.
            RWDNKE
            ENCUU 6CDNKEC
            ]
              RTKXCVG KPV=? VCDNKEC  PGY KPV=?
              RWDNKE KPV RQDKGT'NGOGPV
KPV KPFGMU
              ]
                     TGVWTP VCDNKEC=KPFGMU?
              _
              RWDNKE XQKF WUVCY'NGOGPV
KPV KPFGMU KPV YCTVQUE
              ]
                     VCDNKEC=KPFGMU?  YCTVQUE
              _
            _

            RWDNKE
            ENCUU /CKP
            ]
              RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
              ]
                     6CDNKEC VCDNKEC  PGY 6CDNKEC

                     VCDNKECWUVCY'NGOGPV
 
                     KPV NKEDC  VCDNKECRQDKGT'NGOGPV

                     5[UVGOQWVRTKPVNP
NKEDC
              _
            _


         Powstały tu dwie klasy: 6CDNKEC oraz /CKP. W klasie 6CDNKEC zostało zadeklarowane
         prywatne pole typu tablicowego o nazwie VCDNKEC, któremu została przypisana dzie-
         sięcioelementowa tablica liczb całkowitych. Poniewa pole to jest polem prywatnym
         (por. lekcja 17.), dostęp do niego mają jedynie inne składowe klasy 6CDNKEC. Dlatego
         te powstały dwie metody RQDKGT'NGOGPV oraz WUVCY'NGOGPV operujące na elemen-
         tach tablicy. Metoda RQDKGT'NGOGPV zwraca wartość zapisaną w komórce o indeksie
         przekazanym jako argument, natomiast WUVCY'NGOGPV zapisuje wartość drugiego argu-
         mentu w komórce o indeksie wskazywanym przez argument pierwszy.

         W klasie /CKP tworzymy obiekt klasy 6CDNKEC i wykorzystujemy metodę WUVCY'NGOGPV
         do zapisania w piątej komórce wartości . W kolejnej linii popełniamy drobny błąd.
         W metodzie RQDKGT'NGOGPV odwołujemy się do nieistniejącego elementu o indeksie
         . Musi to spowodować wystąpienie błędu w trakcie działania aplikacji (rysunek 4.1).
         Błąd tego typu bardzo łatwo popełnić, gdy w klasie /CKP nie widzimy rozmiarów
         tablicy, nietrudno więc o pomyłkę.

Rysunek 4.1.
Odwołanie
do nieistniejącego
elementu
w klasie Tablica
Rozdział 4. ♦ Wyjątki                                                                              155


           Jak poradzić sobie z takim problemem? Pierwszym nasuwającym się sposobem jest
           sprawdzanie w metodach RQDKGT'NGOGPV i WUVCY'NGOGPV, czy przekazane argumenty
           nie przekraczają dopuszczalnych wartości. Jeśli takie przekroczenie wartości nastąpi,
           nale y wtedy zasygnalizować błąd. To jednak prowokuje pytanie: w jaki sposób ten
           błąd sygnalizować? Pomysłem znanym programistom C/C++ jest np. zwracanie przez
           funkcję (metodę) wartości  w przypadku błędu oraz wartości nieujemnej (najczę-
           ściej zero), jeśli błąd nie wystąpił1. Ta metoda będzie dobra w przypadku metody
           WUVCY'NGOGPV, która wyglądałaby wtedy następująco:
              RWDNKE KPV WUVCY'NGOGPV
KPV KPFGMU KPV YCTVQUE
              ]
                KH
KPFGMU  VCDNKECNGPIVJ]
                       TGVWTP 
                _
                GNUG]
                       VCDNKEC=KPFGMU?  YCTVQUE
                       TGVWTP 
                _
              _

           Wystarczyłoby teraz w klasie /CKP testować wartość zwróconą przez WUVCY'NGOGPV,
           aby sprawdzić, czy nie przekroczyliśmy dopuszczalnego indeksu tablicy. Niestety, tej
           techniki nie mo na zastosować w przypadku metody RQDKGT'NGOGPV, przecie zwraca
           ona wartość zapisaną w jednej z komórek tablicy. Czyli  i  u yte przed chwilą do
           zasygnalizowania, czy operacja zakończyła się błędem, mogą być wartościami odczyta-
           nymi z tablicy. Trzeba zatem wymyślić inny sposób. Mo e być to np. wykorzystanie
           dodatkowego pola sygnalizującego w klasie 6CDNKEC. Pole to byłoby typu DQQNGCP.
           Ustawione na VTWG oznaczałoby, e ostatnia operacja na klasie zakończyła się błędem,
           natomiast ustawione na HCNUG, e ostatnia operacja zakończyła się sukcesem. Klasa
           6CDNKEC miałaby wtedy postać, jak na listingu 4.2.

Listing 4.2.
              RWDNKE
              ENCUU 6CDNKEC
              ]
                RTKXCVG KPV=? VCDNKEC  PGY KPV=?
                RWDNKE DQQNGCP Y[UVCRKN$NCF  HCNUG
                RWDNKE KPV RQDKGT'NGOGPV
KPV KPFGMU
                ]
                       KH
KPFGMU  VCDNKECNGPIVJ]
                              Y[UVCRKN$NCF  VTWG
                              TGVWTP 
                       _
                       GNUG]
                              Y[UVCRKN$NCF  HCNUG
                              TGVWTP VCDNKEC=KPFGMU?
                       _
                _



1
    To tylko przykład. Równie często stosuje się zwrócenie wartości zero jako oznaczenie prawidłowego
    wykonania funkcji.
156                                                                    Praktyczny kurs Java


               RWDNKE XQKF WUVCY'NGOGPV
KPV KPFGMU KPV YCTVQUE
               ]
                      KH
KPFGMU  VCDNKECNGPIVJ]
                             Y[UVCRKN$NCF  VTWG
                      _
                      GNUG]
                             VCDNKEC=KPFGMU?  YCTVQUE
                             Y[UVCRKN$NCF  HCNUG
                      _
               _
           _


        Do klasy dodaliśmy pole typu DQQNGCP o nazwie Y[UVCRKN$NCF. Jego początkowa
        wartość to HCNUG. W metodzie RQDKGT'NGOGPV sprawdzamy najpierw, czy przekazany
        indeks nie przekracza dopuszczalnej maksymalnej wartości. Jeśli tak, ustawiamy pole
        Y[UVCRKN$NCF na VTWG oraz zwracamy wartość zero. Oczywiście, w tym przypadku
        zwrócona wartość nie ma adnego praktycznego znaczenia (przecie wystąpił błąd),
        niemniej coś musimy zwrócić. U ycie instrukcji TGVWTP i zwrócenie wartości typu KPV
        jest bowiem konieczne, inaczej kompilator zgłosi błąd. Jeśli jednak argument przeka-
        zany metodzie nie przekracza dopuszczalnego indeksu tablicy, pole Y[UVCRKN$NCF
        ustawiamy na HCNUG oraz zwracamy wartość znajdującą się pod tym indeksem.

        W metodzie WUVCY'NGOGPV postępujemy podobnie. Sprawdzamy, czy przekazany indeks
        nie przekracza dopuszczalnej wartości. Jeśli tak, pole Y[UVCRKN$NCF ustawiamy na
        VTWG, w przeciwnym przypadku dokonujemy przypisania wskazanej komórce tablicy
        i ustawiamy Y[UVCRKN$NCF na HCNUG. Po takiej modyfikacji obu metod w klasie /CKP
        mo emy ju bez problemów stwierdzić, czy operacje wykonywane na klasie 6CDNKEC
        zakończyły się sukcesem. Przykładowe wykorzystanie mo liwości, jakie daje nowe
        pole, zostało przedstawione na listingu 4.3.

Listing 4.3.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    6CDNKEC VCDNKEC  PGY 6CDNKEC

                    VCDNKECWUVCY'NGOGPV
 
                    KPV NKEDC  VCDNKECRQDKGT'NGOGPV

                    KH 
VCDNKECY[UVCRKN$NCF]
                           5[UVGOQWVRTKPVNP
 9[UVæRK D æF 
                    _
                    GNUG]
                           5[UVGOQWVRTKPVNP
NKEDC
                    _
             _
           _


        Podstawowe wykonywane operacje są takie same, jak w przypadku klasy z listingu 4.1.
        Po pobraniu elementu sprawdzamy jednak, czy operacja ta zakończyła się sukcesem
        i wyświetlamy odpowiedni komunikat na ekranie. Identyczne sprawdzenie mo na
Rozdział 4. ♦ Wyjątki                                                                                 157


           wykonać równie po wywołaniu metody WUVCY'NGOGPV. Wykonanie kodu z listingu 4.3
           spowoduje rzecz jasna wyświetlenie napisu 9[UVæRK D æF (rysunek 4.2).

Rysunek 4.2.
Efekt wykonania
programu
z listingu 4.3




           Sposobów poradzenia sobie z problemem przekroczenia indeksu tablicy mo na by
           zapewne wymyślić jeszcze kilka. Metody tego typu mają jednak powa ną wadę:
           programiści mają tendencję do ich… niestosowania. Często mo liwy błąd wydaje się
           zbyt banalny, aby się nim zajmować, czasami po prostu się zapomina się o sprawdza-
           niu pewnych warunków. Dodatkowo przedstawione wy ej sposoby, czyli zwracanie
           wartości sygnalizacyjnej czy dodatkowe zmienne, powodują niepotrzebne rozbudo-
           wywanie kodu aplikacji, co paradoksalnie mo e prowadzić do powstawania kolejnych
           błędów, czyli błędów powstałych przez napisanie kodu zajmującego się obsługą błę-
           dów… W Javie zastosowano więc mechanizm tak zwanych wyjątków, znany na pewno
           programistom C++ i Object Pascala2.

Wyjątki w Javie
           Wyjątek (ang. exception) jest to byt programistyczny, który powstaje w sytuacji wy-
           stąpienia błędu. Z powstaniem wyjątku spotkaliśmy się ju w rozdziale 2. w lekcji 11.
           Był to wyjątek spowodowany przekroczeniem dopuszczalnego zakresu tablicy. Po-
           ka my go raz jeszcze. Na listingu 4.4 została zaprezentowana odpowiednio spreparo-
           wana klasa /CKP.

Listing 4.4.
              RWDNKE
              ENCUU /CKP
              ]
                RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
                ]
                       KPV VCD=?  PGY KPV=?
                       VCD=?  
                _
              _


           Deklarujemy tablicę liczb typu KPV o nazwie VCD oraz próbujemy przypisać elementowi
           o indeksie  (czyli wykraczającym poza zakres tablicy) wartość . Jeśli skompilu-
           jemy i uruchomimy taki program, na ekranie zobaczymy obraz widoczny na rysunku 4.3.
           Został tu wygenerowany wyjątek o nazwie #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP, czyli
           wyjątek oznaczający, e indeks tablicy znajduje się poza jej granicami.


2
    Sama technika obsługi sytuacji wyjątkowych sięga jednak lat sześćdziesiątych ubiegłego stulecia
    (czyli wieku XX).
158                                                                                  Praktyczny kurs Java


Rysunek 4.3.
Odwołanie
do nieistniejącego
elementu tablicy
spowodowało
wygenerowanie
wyjątku

           Oczywiście, gdyby mo liwości wyjątków kończyłyby się na wyświetlaniu informacji
           na ekranie i przerywaniu działania programu, ich przydatność byłaby mocno ograni-
           czona. Na szczęście, wygenerowany wyjątek mo na przechwycić i wykonać własny kod
           obsługi błędu. Do takiego przechwycenia słu y blok instrukcji VT[ECVEJ. W naj-
           prostszej postaci wygląda on następująco:
              VT[]
                KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM
              _
              ECVEJ 
6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW]
                QDU WIC Y[LæVMW
              _

           W nawiasach klamrowych występujących po słowie VT[ umieszczamy instrukcję,
           która mo e spowodować wystąpienie wyjątku. W bloku występującym po ECVEJ
           umieszczamy kod, który ma zostać wykonany, kiedy wyjątek wystąpi. W przypadku
           klasy /CKP z listingu 4.4 blok VT[ECVEJ nale ałoby zastosować sposób przedsta-
           wiony na listingu 4.5.

Listing 4.5.
              RWDNKE
              ENCUU /CKP
              ]
                RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
                ]
                       KPV VCD=?  PGY KPV=?
                       VT[]
                              VCD=?  
                       _
                       ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                              5[UVGOQWVRTKPVNP
 0KGRTCYKF QY[ KPFGMU VCDNKE[ 
                       _
                _
              _


           Jak widać, wszystko odbywa się tu zgodnie z wcześniejszym ogólnym opisem. W bloku
           VT[ znalazła się instrukcja VCD=?  , która — jak wiemy — spowoduje wygene-
           rowanie wyjątku. W nawiasach okrągłych występujących po instrukcji ECVEJ został
           wymieniony rodzaj wyjątku, który zostanie wygenerowany: #TTC[+PFGZ1WV1H$QWPFU
                                                                          3
           å'ZEGRVKQP, oraz jego identyfikator: G. Identyfikator to nazwa , która pozwala na
           wykonywanie operacji związanych z wyjątkiem, czym jednak zajmiemy się w kolejnej

3
    Dokładniej jest to nazwa zmiennej obiektowej, wyjaśnimy to bli ej w lekcji 21.
Rozdział 4. ♦ Wyjątki                                                                        159


        lekcji. W bloku po ECVEJ znajduje się instrukcja 5[UVGOQWVRTKPVNP wyświetlająca
        odpowiedni komunikat na ekranie. Tym razem po uruchomieniu kodu zobaczmy widok
        zaprezentowany na rysunku 4.4.

Rysunek 4.4.
Wyjątek został
przechwycony
w bloku try…catch




        Blok VT[ECVEJ nie musi jednak obejmować tylko jednej instrukcji ani te tylko in-
        strukcji mogących wygenerować wyjątek. Przypomnijmy ponownie listing 2.38. Blok
        VT[ mógłby w tym wypadku objąć wszystkie trzy instrukcje, czyli klasa /CKP miałaby
        wtedy postać jak na listingu 4.6.

Listing 4.6.
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VT[]
                          KPV VCD=?  PGY KPV=?
                          VCD=?  
                          5[UVGOQWVRTKPVNP
 KGUKæV[ GNGOGPV VCDNKE[ OC YCTVQ è   
 VCD=?
                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 0KGRTCYKF QY[ KPFGMU VCDNKE[ 
                    _
             _
           _


        Nie istnieje równie konieczność obejmowania blokiem VT[ instrukcji bezpośrednio
        generujących wyjątek, tak jak miało to miejsce w dotychczasowych przykładach. Wyjątek
        wygenerowany przez obiekt klasy ; mo e być bowiem przechwytywany w klasie :,
        która korzysta z obiektów klasy ;. Poka emy to na przykładzie klas z listingu 4.1.
        Klasa 6CDNKEC pozostanie bez zmian, natomiast klasę /CKP zmodyfikujemy tak, aby
        miała wygląd zaprezentowany na listingu 4.7.

Listing 4.7.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    6CDNKEC VCDNKEC  PGY 6CDNKEC

                    VT[]
                           VCDNKECWUVCY'NGOGPV
 
                           KPV NKEDC  VCDNKECRQDKGT'NGOGPV

                           5[UVGOQWVRTKPVNP
NKEDC
                    _
160                                                                     Praktyczny kurs Java


                   ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                          5[UVGOQWVRTKPVNP
 0KGRTCYKF QY[ KPFGMU VCDNKE[ 
                   _
               _
           _


        Spójrzmy, w bloku VT[ wykonujemy trzy instrukcje, z których jedna: KPV NKEDC 
        VCDNKECRQDKGT'NGOGPV
 jest odpowiedzialna za wygenerowanie wyjątku. Wyją-
        tek jest przecie jednak generowany w ciele metody RQDKGT'NGOGPV klasy 6CDNKEC, a nie
        w klasie /CKP! Zostanie on jednak przekazany klasie /CKP, jako e wywołuje ona metodę
        klasy 6CDNKEC. Tym samym w klasie /CKP mo emy zastosować blok VT[ECVEJ.

        Z identyczną sytuacją będziemy mieli do czynienia w przypadku hierarchicznego
        wywołania metod jednej klasy. Czyli w sytuacji, kiedy metoda H wywołuje metodę I,
        która wywołuje metodę J, która z kolei generuje wyjątek. W ka dej z wymienionych
        metod mo na zastosować blok VT[ECVEJ do przechwycenia tego wyjątku. Dokładnie
        taki przykład jest widoczny na listingu 4.8.

Listing 4.8.
           RWDNKE
           ENCUU 'ZCORNG
           ]
             RWDNKE XQKF H

             ]
                    VT[]
                           I

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC H 
                    _
             _
             RWDNKE XQKF I

             ]
                    VT[]
                           J

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC I 
                    _
             _
             RWDNKE XQKF J

             ]
                    KPV=? VCD  PGY KPV=?
                    VT[]
                           VCD=?  
                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC J 
                    _
             _
             RWDNKE UVCVKE XQKF OCKP
5VTKPI CTIU=?
             ]
                    'ZCORNG GZ  PGY 'ZCORNG
Rozdział 4. ♦ Wyjątki                                                                     161


                    VT[]
                           GZH

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC OCKP 
                    _
              _
          _


        Taką klasę skompilujemy bez adnych problemów. Musimy jednak dobrze zdawać
        sobie sprawę, jak taki kod będzie wykonywany. Pytanie bowiem brzmi: które bloki
        VT[ zostaną wykonane? Zasada jest następująca: zostanie wykonany blok najbli szy
        instrukcji powodującej wyjątek. Czyli w przypadku przedstawionym na listingu 4.8
        jedynie blok obejmujący wywołanie metody VCD=?   w metodzie J. Jeśli jednak
        będziemy usuwać kolejne bloki VT[ najpierw z instrukcji J, następnie I, H i ostatecznie
        z OCKP, zobaczymy, e faktycznie wykonywany jest zawsze blok najbli szy miejsca
        wystąpienia błędu. Po usunięciu wszystkich instrukcji VT[ wyjątek nie zostanie obsłu-
         ony w naszej klasie i obsłu y go maszyna wirtualna Javy, co zaowocuje znanym nam
        ju komunikatem na konsoli. Zwróćmy jednak uwagę, e w tym wypadku zostanie wy-
        świetlona cała hierarchia metod, w których był propagowany wyjątek (rysunek 4.5).

Rysunek 4.5.
Przy
hierarchicznym
wywołaniu metod
po wystąpieniu
wyjątku otrzymamy
ich nazwy



Ćwiczenia do samodzielnego wykonania
        20.1. Popraw kod klasy z listingu 4.2 tak, aby w metodach RQDKGT'NGOGPV i WUVCY'NGOGPV
        było równie sprawdzane, czy przekazany indeks nie przekracza minimalnej dopusz-
        czalnej wartości.

        20.2. Zmień kod klasy /CKP z listingu 4.3 w taki sposób, aby było równie sprawdzane,
        czy wywołanie metody WUVCY'NGOGPV zakończyło się sukcesem.

        20.3. Popraw kod z listingu 4.2 tak, aby do wychwytywania błędów był wykorzysty-
        wany mechanizm wyjątków zamiast instrukcji warunkowej KH.

        20.4. Napisz klasę 'ZCORNG, w której będzie się znajdowała metoda o nazwie C, która
        z kolei będzie wywoływała metodę o nazwie D. W metodzie C wygeneruj wyjątek
        #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP. Napisz następnie klasę /CKP zawierającą metodę
        OCKP, w której zostanie utworzony obiekt klasy 'ZCORNG i zostaną wywołane metody
        C oraz D tego obiektu. W metodzie OCKP zastosuj bloki VT[ECVEJ, przechwytujące
        powstały wyjątek.
162                                                                      Praktyczny kurs Java


Lekcja 21. Wyjątki to obiekty
         W lekcji 20. poznaliśmy wyjątek sygnalizujący przekroczenie dopuszczalnego zakresu
         tablicy. To oczywiście nie jedyny dostępny wyjątek, czas poznać równie inne ich typy.
         W lekcji 21. dowiemy się więc, e wyjątki są tak naprawdę obiektami, a tak e, e tworzą
         one hierarchiczną strukturę. Poka emy, jak przechwytywać wiele wyjątków w jednym
         bloku VT[ oraz udowodnimy, e bloki VT[ECVEJ mogą być zagnie d ane. Oka e się,
          e jeden wyjątek ogólny mo e obsłu yć wiele błędnych sytuacji.

Dzielenie przez zero
         Rodzajów wyjątków jest bardzo wiele. Wiemy ju , jak reagować na przekroczenie
         zakresu tablicy. Poznajmy zatem inny typ wyjątku, powstający, kiedy zostanie podjęta
         próba wykonania nielegalnego dzielenia przez zero. W tym celu musimy spreparować
         odpowiedni fragment kodu. Wystarczy, e w metodzie OCKP umieścimy przykładową
         instrukcję:
            KPV NKEDC    .

         Kompilacja takiego kodu przebiegnie bez problemu, jednak próba wykonania musi
         skończyć się komunikatem o błędzie, widocznym na rysunku 4.6. Widzimy wyraźnie,
          e tym razem został zgłoszony wyjątek #TKVJOGVKE'ZEGRVKQP (wyjątek arytmetyczny).

Rysunek 4.6.
Próba wykonania
dzielenia przez zero




         Wykorzystując wiedzę z lekcji 20., nie powinniśmy mieć adnych problemów z napi-
         saniem kodu, który taki wyjątek przechwyci. Trzeba wykorzystać dobrze nam znaną
         instrukcję VT[ECVEJ w postaci:
            VT[]
              KPV NKEDC    
            _
            ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
              KPUVTWMELG FQ Y[MQPCPKC MKGF[ Y[UVæRK Y[LæVGM
            _

         Intuicja podpowiada nam ju zapewne, e rodzajów wyjątków mo e być bardzo, bardzo
         du o. I faktycznie tak jest, w klasach dostarczonych w JDK (w wersji SE) jest ich
         zdefiniowanych blisko 300. Aby sprawnie się nimi posługiwać, musimy dowiedzieć
         się, czym tak naprawdę są wyjątki.

Wyjątek jest obiektem
         Wyjątek, który określaliśmy jako byt programistyczny, to nic innego jak obiekt,
         który powstaje, kiedy w programie wystąpi sytuacja wyjątkowa. Skoro wyjątek jest
Rozdział 4. ♦ Wyjątki                                                                     163


        obiektem, to wspominany wcześniej typ wyjątku (#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP,
        #TKVJOGVKE'ZEGRVKQP) to nic innego jak klasa opisująca ten e obiekt. Jeśli teraz spoj-
        rzymy ponownie na ogólną postać instrukcji VT[ECVEJ:
           VT[]
             KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM
           _
           ECVEJ
6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW]
             QDU WIC Y[LæVMW
           _

        jasnym stanie się, e w takim razie KFGPV[HKMCVQT9[LæVMW to zmienna obiektowa, wska-
        zująca na obiekt wyjątku. Na tym obiekcie mo emy wykonywać operacje zdefiniowane
        w klasie wyjątku. Mo emy np. uzyskać systemowy komunikat o błędzie. Wystarczy
        wywołać metodę IGV/GUUCIG
. Zobaczmy to na przykładzie wyjątku generowanego
        podczas próby wykonania dzielenia przez zero. Jest on zaprezentowany na listingu 4.9.

Listing 4.9.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VT[]
                           KPV NKEDC    
                    _
                    ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[UVCRK Y[LæVGM CT[VOGV[EP[ 
                           5[UVGOQWVRTKPVNP
 -QOWPKMCV U[UVGOQY[ 
                           5[UVGOQWVRTKPVNP
GIGV/GUUCIG

                    _
             _
           _


        Wykonujemy tutaj próbę niedozwolonego dzielenia przez zero oraz przechwytujemy
        wyjątek klasy #TKVJOGVKE'ZEGRVKQP. W bloku ECVEJ najpierw wyświetlamy nasze
        własne komunikaty o błędzie, a następnie komunikat systemowy. Po uruchomieniu
        kodu na ekranie zobaczymy widok zaprezentowany na rysunku 4.7.

Rysunek 4.7.
Wyświetlenie
systemowego
komunikatu obłędzie




        Istnieje jeszcze jedna mo liwość uzyskania komunikatu o wyjątku, mianowicie umiesz-
        czenie w argumencie instrukcji 5[UVGOQWVRTKPVNP zmiennej wskazującej na obiekt
        wyjątku, czyli w przypadku listingu 4.9:
           5[UVGOQWVRTKPVNP
G
164                                                                       Praktyczny kurs Java


        W pierwszej chwili mo e się to wydawać nieco dziwne, bo niby skąd instrukcja
        5[UVGOQWVRTKPVNP ma wiedzieć, co w takiej sytuacji wyświetlić? Zauwa my jednak,
         e jest to sytuacja analogiczna, jak w przypadku typów prostych (por. lekcja 5.). Skoro
        udawało się automatycznie przekształcać np. zmienną typu KPV na ciąg znaków, uda
        się równie przekształcić zmienną typu obiektowego. Bli ej tym problemem zajmiemy
        się w rozdziale piątym.

        Jeśli teraz z programie z listingu 4.9 zamienimy instrukcję:
           5[UVGOQWVRTKPVNP
GIGV/GUUCIG


        na:
           5[UVGOQWVRTKPVNP
G

        otrzymamy nieco dokładniejszy komunikat określający dodatkowo klasę wyjątku, tak
        jak jest to widoczne na rysunku 4.8.

Rysunek 4.8.
Pełniejszy komunikat
o typie wyjątku




Hierarchia wyjątków
        Ka dy wyjątek jest obiektem pewnej klasy. Klasy podlegają z kolei regułom dziedzi-
        czenia, zgodnie z którymi powstaje hierarchia klas. Kiedy zatem pracujemy z wyjątkami,
        musimy tę kwestię wziąć pod uwagę. Wszystkie standardowe wyjątki, które mo emy
        przechwytywać w naszych aplikacjach za pomocą bloku VT[ECVEJ, dziedziczą z klasy
        'ZEGRVKQP, która z kolei dziedziczy z 6JTQYCDNG oraz 1DLGEV. Hierarchia klas dla wyjątku
        #TKVJOGVKE'ZEGRVKQP, który wykorzystywaliśmy we wcześniejszych przykładach, jest
        zaprezentowana na rysunku 4.9.

Rysunek 4.9.
Hierarchia klas
dla wyjątku
ArithmeticException




        Wynika z tego kilka własności. Przede wszystkim, jeśli spodziewamy się, e dana
        instrukcja mo e wygenerować wyjątek typu :, mo emy zawsze przechwycić wyjątek
        ogólniejszy, czyli wyjątek, którego typem będzie jedna z klas nadrzędnych do :. Jest
        to bardzo wygodna technika. Przykładowo z klasy 4WPVKOG'ZEGRVKQP dziedziczy bar-
        dzo wiele klas wyjątków odpowiadających najró niejszym błędom. Jedną z nich jest
        #TKVJOGVKE'ZEGRVKQP. Jeśli instrukcje, które obejmujemy blokiem VT[ECVEJ, mogą
Rozdział 4. ♦ Wyjątki                                                                    165


        spowodować wiele ró nych wyjątków, zamiast stosować wiele oddzielnych instrukcji
        przechwytujących konkretne typy błędów, często lepiej jest zastosować jedną prze-
        chwytującą wyjątek bardziej ogólny. Spójrzmy na listing 4.10.

Listing 4.10.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VT[]
                           KPV NKEDC    
                    _
                    ECVEJ
4WPVKOG'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[UVCRK Y[LæVGM ECUW Y[MQPCPKC 
                           5[UVGOQWVRTKPVNP
 -QOWPKMCV U[UVGOQY[ 
                           5[UVGOQWVRTKPVNP
G
                    _
             _
           _


        Jest to znany nam ju program, generujący błąd polegający na próbie wykonania
        niedozwolonego dzielenia przez zero. Tym razem jednak zamiast wyjątku klasy
        #TKVJOGVKE'ZEGRVKQP przechwytujemy wyjątek klasy nadrzędnej 4WPVKOG'ZEGRVKQP.
        Co więcej, nic nie stoi na przeszkodzie, aby przechwycić wyjątek jeszcze ogólniejszy,
        czyli wyjątek klasy nadrzędnej do 4WPVKOG'ZEGRVKQP. Jak widać na rysunku 4.9, byłaby
        to klasa 'ZEGRVKQP.

Przechwytywanie wielu wyjątków
        W jednym bloku VT[ECVEJ mo na przechwytywać wiele wyjątków. Konstrukcja
        taka zawiera wtedy jeden blok VT[ i wiele bloków ECVEJ. Schematycznie wygląda ona
        następująco:
           VT[]
             KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM
           _
           ECVEJ
-NCUC9[LæVMW KFGPV[HKMCVQT9[LæVMW]
             QDU WIC Y[LæVMW 
           _
             ECVEJ
-NCUC9[LæVMW KFGPV[HKMCVQT9[LæVMW]
             QDU WIC Y[LæVMW 
           _
FCNUG DNQMK ECVEJ
ECVEJ
-NCUC9[LæVMW P KFGPV[HKMCVQT9[LæVMWP]
             QDU WIC Y[LæVMW P
           _

        Po wygenerowaniu wyjątku jest sprawdzane, czy jest on klasy -NCUC9[LCVMW, jeśli tak
        — są wykonywane instrukcje obsługi tego wyjątku i blok VT[ECVEJ jest opuszczany.
        Je eli jednak wyjątek nie jest klasy -NCUC9[LCVMW, jest sprawdzane, czy jest on klasy
        -NCUC9[LæVMW itd.
166                                                                       Praktyczny kurs Java


        Przy tego typu konstrukcjach nale y jednak pamiętać o hierarchii wyjątków, nie jest
        bowiem obojętne, w jakiej kolejności będą one przechwytywane. Ogólna zasada jest
        taka, e nie ma znaczenia kolejność, o ile wszystkie wyjątki są na jednym poziomie
        hierarchii. Jeśli jednak przechwytujemy wyjątki z ró nych poziomów, najpierw muszą
        to być wyjątki bardziej szczegółowe, czyli stojące ni ej w hierarchii, a dopiero po nich
        wyjątki bardziej ogólne, czyli stojące wy ej w hierarchii.

        Nie mo na zatem najpierw przechwycić wyjątku 4WPVKOG'ZEGRVKQP, a dopiero nim
        wyjątku #TKVJOGVKE'ZEGRVKQP (por. rysunek 4.9), gdy skończy się to błędem kompi-
        lacji. Jeśli więc dokonamy próby kompilacji przykładowego programu przedstawionego
        na listingu 4.11, efektem będą komunikaty widoczne na rysunku 4.10.

Listing 4.11.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VT[]
                           KPV NKEDC    
                    _
                    ECVEJ
4WPVKOG'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
G
                    _
                    ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
G
                    _
             _
           _


Rysunek 4.10.
Błędna hierarchia
wyjątków powoduje
błąd kompilacji




        Dzieje się tak dlatego, e (mo na powiedzieć) błąd bardziej ogólny zawiera ju
        w sobie błąd bardziej szczegółowy. Jeśli zatem przechwytujemy najpierw wyjątek
        4WPVKOG'ZEGRVKQP, to tak jak byśmy przechwycili ju wyjątki wszystkich klas dziedzi-
        czących z 4WPVKOG'ZEGRVKQP. Dlatego te kompilator protestuje.

        Kiedy jednak mo e przydać się sytuacja, e najpierw przechwytujemy wyjątek szcze-
        gółowy, a potem dopiero ogólny? Otó , wtedy, kiedy chcemy w specyficzny sposób
        zareagować na konkretny typ wyjątku, a wszystkie pozostałe z danego poziomu hie-
        rarchii obsłu yć w identyczny, standardowy sposób. Taka przykładowa sytuacja jest
        przedstawiona na listingu 4.12.
Rozdział 4. ♦ Wyjątki                                                                     167


Listing 4.12.
            RWDNKE
            ENCUU /CKP
            ]
              RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
              ]
                     2WPMV RWPMV  PWNN
                     KPV NKEDC
                     VT[]
                            NKEDC    
                            RWPMVZ  NKEDC
                     _
                     ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                            5[UVGOQWVRTKPVNP
 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC 
                            5[UVGOQWVRTKPVNP
G
                     _
                     ECVEJ
'ZEGRVKQP G]
                            5[UVGOQWVRTKPVNP
 $ æF QIÎNP[ 
                            5[UVGOQWVRTKPVNP
G
                     _
              _
            _


         Zostały zadeklarowane dwie zmienne: pierwsza typu 2WPMV o nazwie RWPMV oraz druga
         typu KPV o nazwie NKEDC. Zmiennej RWPMV została przypisana wartość pusta PWNN, nie
         został zatem utworzony aden obiekt klasy 2WPMV. W bloku VT[ są wykonywane dwie
         błędne instrukcje. Pierwsza z nich to znane nam z poprzednich przykładów dzielenie
         przez zero. Druga instrukcja z bloku VT[ to z kolei próba odwołania się do pola Z nie-
         istniejącego obiektu klasy 2WPMV (przecie zmienna RWPMV zawiera wartość PWNN). Ponie-
         wa chcemy w sposób niestandardowy zareagować na błąd arytmetyczny, najpierw
         przechwytujemy błąd typu #TKVJOGVKE'ZEGRVKQP i, w przypadku kiedy wystąpi, wyświe-
         tlamy na ekranie napis 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC. W drugim bloku ECVEJ
         przechwytujemy wszystkie inne mo liwe wyjątki, w tym tak e wyjątek 0WNN2QKPVGT
         å'ZEGRVKQP występujący, kiedy próbujemy wykonać operacje na zmiennej obiektowej,
         która zawiera wartość PWNN.

         Po uruchomieniu kodu z listingu 4.12 na ekranie pojawi się zgłoszenie tylko pierwszego
         błędu. Dzieje się tak dlatego, e po jego wystąpieniu blok VT[ został przerwany, a ste-
         rowanie zostało przekazane blokowi ECVEJ. Czyli jeśli w bloku VT[ któraś z instrukcji
         spowoduje wygenerowanie wyjątku, dalsze instrukcje z bloku VT[ nie zostaną wykonane.
         Nie miała więc szansy zostać wykonana nieprawidłowa instrukcja RWPMVZ  NKEDC.
         Jeśli jednak usuniemy wcześniejsze dzielenie przez zero, przekonamy się, e i ten błąd
         zostanie przechwycony przez drugi blok ECVEJ, a na ekranie pojawi się stosowny komu-
         nikat (rysunek 4.11).

Rysunek 4.11.
Odwołanie do pustej
zmiennej obiektowej
zostało wychwycone
przez drugi blok catch
168                                                                      Praktyczny kurs Java


Zagnieżdżanie bloków try...catch
        Bloki VT[ECVEJ mo na zagnie d ać. To znaczy, e w jednym bloku przechwytują-
        cym wyjątek : mo e istnieć drugi blok, który będzie przechwytywał wyjątek ;. Sche-
        matycznie taka konstrukcja wygląda następująco:
           VT[]
             KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM 
             VT[]
                    KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM 
             _
             ECVEJ 
6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW]
                    QDU WIC Y[LæVMW 
             _
           _
           ECVEJ 
6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW]
             QDU WIC Y[LæVMW 
           _

        Zagnie d enie takie mo e być wielopoziomowe, czyli w ju zagnie d onym bloku
        VT[ mo na umieścić kolejny blok VT[, choć w praktyce takich piętrowych konstrukcji
        zazwyczaj się nie stosuje. Zwykle nie ma takiej potrzeby. Maksymalny poziom takiego
        bezpośredniego zagnie d enia z reguły nie przekracza dwóch poziomów. Aby na prak-
        tycznym przykładzie pokazać taką dwupoziomową konstrukcję, zmodyfikujemy przy-
        kład z listingu 4.12. Zamiast obejmowania jednym blokiem VT[ dwóch instrukcji powo-
        dujących błąd, zastosujemy zagnie d enie, tak jak jest to widoczne na listingu 4.13.

Listing 4.13.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    2WPMV RWPMV  PWNN
                    KPV NKEDC
                    VT[]
                           VT[]
                                  NKEDC    
                           _
                           ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                                  5[UVGOQWVRTKPVNP
 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC 
                                  5[UVGOQWVRTKPVNP
 2T[RKUWLú OKGPPGLNKEDC YCTVQ è  
                                  NKEDC  
                           _

                           RWPMVZ  NKEDC
                    _
                    ECVEJ
'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 $ æF QIÎNP[ 
                           5[UVGOQWVRTKPVNP
G
                    _
                _
           _
Rozdział 4. ♦ Wyjątki                                                                    169


        Podobnie jak w poprzednim przypadku, deklarujemy dwie zmienne: RWPMV klasy 2WPMV
        oraz NKEDC typu KPV. Zmiennej RWPMV przypisujemy wartość pustą PWNN. W wewnętrznym
        bloku VT[ próbujemy wykonać nieprawidłowe dzielenie przez zero i przechwytujemy
        wyjątek #TKVJOGVKE'ZEGRVKQP. Jeśli on wystąpi, zmienna NKEDC otrzymuje domyślną
        wartość równą , dzięki czemu mo na wykonać kolejną operację, czyli próbę przypi-
        sania polu Z obiektu RWPMV wartości zmiennej NKEDC. Rzecz jasna, przypisanie takie
        nie mo e zostać wykonane, gdy zmienna RWPMV jest pusta, jest zatem generowany
        wyjątek 0WNN2QKPVGT'ZEGRVKQP, który jest przechwytywany przez zewnętrzny blok VT[.
        Widać więc, e zagnie d anie bloków VT[ mo e być przydatne, choć warto zauwa yć,
         e identyczny efekt mo na osiągnąć, korzystając równie z niezagnie d onej postaci
        instrukcji VT[ECVEJ (por. ćwiczenie 21.3).

Ćwiczenia do samodzielnego wykonania
        21.1. Popraw kod z listingu 4.11 tak, aby przechwytywanie wyjątków odbywało się
        w prawidłowej kolejności.

        21.2. Zmodyfikuj kod z listingu 4.12 tak, aby zostały zgłoszone oba typy błędów:
        #TKVJOGVKE'ZEGRVKQP oraz 0WNN2QKPVGT'ZEGRVKQP.

        21.3. Zmodyfikuj kod z listingu 4.5 w taki sposób, aby usunąć zagnie d enie bloków
        VT[ECVEJ, nie zmieniając jednak efektów działania programu.


Lekcja 22. Własne wyjątki
        Wyjątki mo emy przechwytywać, aby zapobiec niekontrolowanemu zakończeniu
        programu w przypadku wystąpienia błędu. Tą technikę poznaliśmy w lekcjach 20. i 21.
        Okazuje się jednak, e mo na je równie samemu zgłaszać, a tak e e mo na tworzyć
        nowe, nieistniejące wcześniej klasy wyjątków. Tej właśnie tematyce jest poświęcona
        bie ąca, 22., lekcja.

Zgłoś wyjątek
        Wiemy, e wyjątki są obiektami. Skoro tak, zgłoszenie własnego wyjątku będzie po-
        legało po prostu na utworzeniu nowego obiektu klasy opisującej wyjątek. Dokładniej za
        pomocą instrukcji PGY nale y utworzyć nowy obiekt klasy, która pośrednio lub bezpo-
        średnio dziedziczy z klasy 6JTQYCDNG. W najbardziej ogólnym przypadku będzie to klasa
        'ZEGRVKQP. Tak utworzony obiekt musi stać się parametrem instrukcji VJTQY. Jeśli zatem
        gdziekolwiek w pisanym przez nas kodzie chcemy zgłosić wyjątek ogólny, wystarczy,
         e napiszemy:
          VJTQY PGY 'ZEGRVKQP


        W specyfikacji metody musimy jednak zaznaczyć, e będziemy w niej zgłaszać wyjątek
        danej klasy. Robimy to za pomocą instrukcji VJTQYU, w ogólnej postaci:
          URGE[HKMCVQTAFQUVGRW =UVCVKE? =HKPCN? V[RAYCTCECP[ PCYCAOGVQF[
CTIWOGPV[
          VJTQYU -NCUC9[LæVMW -NCUC9[LæVMW  -NCUC9[LCVMWP
          ]
            VTG è OGVQF[
          _
170                                                                  Praktyczny kurs Java


        Zobaczmy, jak to wygląda w praktyce. Załó my, e mamy klasę /CKP, a w niej metodę
        OCKP. Jedynym zadaniem tej metody będzie zgłoszenie wyjątku klasy 'ZEGRVKQP. Klasa
        taka jest widoczna na listingu 4.14.

Listing 4.14.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             VJTQYU 'ZEGRVKQP
             ]
                    VJTQY PGY 'ZEGRVKQP

             _
           _


        W deklaracji metody OCKP zaznaczyliśmy, e mo e ona generować wyjątek klasy
        'ZEGRVKQP poprzez u ycie instrukcji VJTQYU 'ZEGRVKQP. W ciele metody OCKP została
        natomiast wykorzystana instrukcja VJTQY, która jako parametr otrzymała nowy obiekt
        klasy 'ZEGRVKQP. Po uruchomieniu takiego programu na ekranie zobaczymy widok
        zaprezentowany na rysunku 4.12. Jest to najlepszy dowód, e faktycznie udało nam
        się zgłosić wyjątek.

Rysunek 4.12.
Zgłoszenie wyjątku
klasy Exception




        Utworzenie obiektu wyjątku nie musi mieć miejsca bezpośrednio w instrukcji VJTQY,
        mo na utworzyć go wcześniej, przypisać zmiennej obiektowej i dopiero tę zmienną
        wykorzystać jako parametr dla VJTQY. Czyli zamiast pisać:
           VJTQY PGY 'ZEGRVKQP


        mo emy równie dobrze zastosować konstrukcję:
           'ZEGRVKQP GZEGRVKQP  PGY 'ZEGRVKQP

           VJTQY GZEGRVKQP

        W obu przedstawionych przypadkach efekt będzie identyczny, najczęściej korzystamy
        jednak z pierwszego zaprezentowanego sposobu.

        Jeśli chcemy, aby zgłaszany wyjątek otrzymał komunikat, nale y przekazać go jako
        parametr konstruktora klasy 'ZEGRVKQP, czyli napiszemy wtedy:
           VJTQY PGY 'ZEGRVKQP
 MQOWPKMCV 

        lub:
           'ZEGRVKQP GZEGRVKQP  PGY 'ZEGRVKQP
 MQOWPKMCV 
           VJTQY GZEGRVKQP
Rozdział 4. ♦ Wyjątki                                                                     171


        Oczywiście, mo na tworzyć obiekty wyjątków klas dziedziczących z 'ZEGRVKQP.
        Przykładowo: jeśli sami wykryjemy próbę dzielenia przez zero, być mo e zechcemy
        wygenerować nasz wyjątek, nie czekając, a zgłosi go maszyna wirtualna. Spójrzmy
        na listing 4.15.

Listing 4.15.
           RWDNKE
           ENCUU 'ZCORNG
           ]
             RWDNKE FQWDNG H
KPV NKEDC KPV NKEDC
             ]
                    KH
NKEDC  
                           VJTQY PGY #TKVJOGVKE'ZEGRVKQP
 KGNGPKG RTG GTQ   
 NKEDC 
                                
 NKEDC
                    TGVWTP NKEDC  NKEDC
             _
             RWDNKE UVCVKE XQKF OCKP
5VTKPI CTIU=?
             ]
                    'ZCORNG GZCORNG  PGY 'ZCORNG

                    KPV Y[PKM  GZCORNGH
 
                    5[UVGOQWVRTKPVNP
 9[PKM RKGTYUGIQ FKGNGPKC 
 Y[PKM
                    Y[PKM  GZCORNGH
 
                    5[UVGOQWVRTKPVNP
 9[PKM FTWIKGIQ FKGNGPKC 
 Y[PKM
             _
           _


        W klasie 'ZCORNG jest zdefiniowana metoda H, która przyjmuje dwa argumenty typu KPV.
        Ma ona zwracać wynik dzielenia wartości przekazanej w argumencie NKEDC przez
        wartość przekazaną w argumencie NKEDC. Jest zatem jasne, e NKEDC nie mo e mieć
        wartości zero. Sprawdzamy to, wykorzystując instrukcję warunkową KH. Jeśli oka e
        się, e NKEDC ma jednak wartość zero, za pomocą instrukcji VJTQY wyrzucamy nowy
        wyjątek klasy #TKVJOGVKE'ZEGRVKQP. W konstruktorze klasy przekazujemy komunikat
        informujący o dzieleniu przez zero. Podajemy w nim wartości argumentów metody H,
        tak by łatwo mo na było stwierdzić, jakie parametry spowodowały błąd.

        W celu przetestowania działania metody H w klasie 'ZCORNG pojawiła się równie metoda
        OCKP. Tworzymy w niej nowy obiekt klasy 'ZCORNG i przypisujemy go zmiennej o nazwie
        GZCORNG. Następnie dwukrotnie wywołujemy metodę H, raz przekazując jej argumenty
        równe  i , drugi raz przekazując jej argumenty równe  i . Spodziewamy się, e
        w drugim przypadku program zgłosi wyjątek #TKVJOGVKE'ZEGRVKQP ze zdefiniowanym
        przez nas komunikatem. Faktycznie program zachowa się w taki właśnie sposób, co
        jest widoczne na rysunku 4.13.

Rysunek 4.13.
Zgłoszenie
własnego
wyjątku klasy
ArithmeticException
172                                                                       Praktyczny kurs Java


Ponowne zgłoszenie przechwyconego wyjątku
        Wiemy ju , jak przechwytywać wyjątki oraz jak samemu zgłaszać wystąpienie wyjątku.
        To pozwoli nam zapoznać się z techniką ponownego zgłaszania (potocznie: wyrzuca-
        nia) ju przechwyconego wyjątku. Jak pamiętamy, bloki VT[ECVEJ mo na zagnie -
        d ać bezpośrednio, a tak e stosować je w przypadku kaskadowo wywoływanych metod.
        Jeśli jednak na którymkolwiek poziomie przechwytywaliśmy wyjątek, jego obsługa
        ulegała zakończeniu. Nie zawsze jest to korzystne zachowanie, czasami istnieje potrzeba,
        aby po wykonaniu naszego bloku obsługi wyjątek nie był niszczony, ale przekazywany
        dalej. Aby osiągnąć takie zachowanie, musimy zastosować instrukcję VJTQY. Schema-
        tycznie wyglądałoby to następująco:
           VT[]
             KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM
           _
           ECVEJ
V[R6[LæVMW KFGPV[HKMCVQT9[LæVMW]
             KPUVTWMELG QDU WIWLæEG U[VWCELú Y[LæVMQYæ
             VJTQY KPFGV[HKMCVQT9[LæVMW
           _

        Listing 4.16 przedstawia, jak taka sytuacja wygląda w praktyce. W bloku VT[ jest
        wykonywana niedozwolona instrukcja dzielenia przez zero. W bloku ECVEJ najpierw
        wyświetlamy na ekranie informację o przechwyceniu wyjątku, a następnie za pomocą
        instrukcji VJTQY ponownie wyrzucamy (zgłaszamy) przechwycony ju wyjątek. Poniewa
        w programie nie ma ju innego bloku VT[ECVEJ, który mógłby przechwycić ten
        wyjątek, zostanie on obsłu ony standardowo przez maszynę wirtualną. Dlatego te na
        ekranie zobaczymy widok zaprezentowany na rysunku 4.14.

Listing 4.16.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VT[]
                           KPV NKEDC    
                    _
                    ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 6W Y[LæVGM QUVC RTGEJY[EQP[ 
                           VJTQY G
                    _
             _
           _


Rysunek 4.14.
Ponowne zgłoszenie
raz przechwyconego
wyjątku
Rozdział 4. ♦ Wyjątki                                                                     173


        W przypadku zagnie d onych bloków VT[ sytuacja wygląda analogicznie. Wyjątek
        przechwycony w bloku wewnętrznym i ponownie zgłoszony mo e być obsłu ony
        w bloku zewnętrznym, w którym mo e być oczywiście zgłoszony kolejny raz itd. Jest
        to zobrazowane na listingu 4.17.

Listing 4.17.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             ]
                    VW FQYQNPG KPUVTWMELG
                    VT[]
                           VW FQYQNPG KPUVTWMELG
                           VT[]
                                  KPV NKEDC    
                           _
                           ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                                  5[UVGOQWVRTKPVNP
 6W Y[LæVGM QUVC RTGEJY[EQP[ RKGTYU[
                                     TC 
                                  VJTQY G
                           _
                    _
                    ECVEJ
#TKVJOGVKE'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 6W Y[LæVGM QUVC RTGEJY[EQP[ FTWIK TC 
                           VJTQY G
                    _
             _
           _


        Mamy tu dwa zagnie d one bloki VT[. W bloku wewnętrznym zostaje wykonana nie-
        prawidłowa instrukcja dzielenia przez zero. Zostaje ona w tym bloku przechwycona,
        a na ekranie zostaje wyświetlony komunikat o pierwszym przechwyceniu wyjątku.
        Następnie wyjątek jest ponownie zgłaszany. W bloku zewnętrznym następuje drugie
        przechwycenie, wyświetlenie drugiego komunikatu oraz kolejne zgłoszenie wyjątku.
        Poniewa nie istnieje trzeci blok VT[ECVEJ, ostatecznie wyjątek jest obsługiwany
        przez maszynę wirtualną. Po uruchomieniu zobaczymy widok zaprezentowany na
        rysunku 4.15.

Rysunek 4.15.
Przechwytywanie
i ponowne zgłaszanie
wyjątków




        W identyczny sposób będą zachowywały się wyjątki w przypadku kaskadowego wywo-
        ływania metod. Z sytuacją tego typu mieliśmy do czynienia w przypadku przykładu
        z listingu 4.8. W klasie 'ZCORNG były wtedy zadeklarowane cztery metody: OCKP, H, I, J.
        Metoda OCKP wywoływała metodę H, ta z kolei metodę I, a metoda I metodę J. W ka dej
174                                                                        Praktyczny kurs Java


        z metod znajdował się blok VT[ECVEJ, jednak zawsze działał tylko ten najbli szy
        miejsca wystąpienia wyjątku (por. lekcja 20.). Zmodyfikujemy więc kod z listingu 4.8
        tak, aby za ka dym razem wyjątek był po przechwyceniu ponownie zgłaszany. Kod
        realizujący to zadanie jest przedstawiony na listingu 4.18.

Listing 4.18.
           RWDNKE
           ENCUU 'ZCORNG
           ]
             RWDNKE XQKF H

             ]
                    VT[]
                           I

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC   H 
                           VJTQY G
                    _
             _
             RWDNKE XQKF I

             ]
                    VT[]
                           J

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC   I 
                           VJTQY G
                    _
             _
             RWDNKE XQKF J

             ]
                    KPV=? VCD  PGY KPV=?
                    VT[]
                           VCD=?  
                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC   J 
                           VJTQY G
                    _
             _
             RWDNKE UVCVKE XQKF OCKP
5VTKPI CTIU=?
             ]
                    'ZCORNG GZ  PGY 'ZCORNG

                    VT[]
                           GZH

                    _
                    ECVEJ
#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 9[LæVGM OGVQFC   OCKP 
                           VJTQY G
                    _
             _
           _
Rozdział 4. ♦ Wyjątki                                                                   175


        Wszystkie wywołania metod pozostały niezmienione, w ka dym bloku ECVEJ została
        natomiast dodana instrukcja VJTQY ponownie zgłaszająca przechwycony wyjątek. Ry-
        sunek 4.16 pokazuje efekty uruchomienia przedstawionego kodu. Widać wyraźnie, jak
        wyjątek jest propagowany po wszystkich metodach, począwszy od metody J a skoń-
        czywszy na metodzie OCKP. Poniewa w bloku VT[ECVEJ metody OCKP jest on ponow-
        nie zgłaszany, na ekranie jest tak e widoczna reakcja maszyny wirtualnej.

Rysunek 4.16.
Kaskadowe
przechwytywanie
wyjątków




Tworzenie własnych wyjątków
        Programując w Javie, nie musimy zdawać się na wyjątki systemowe, które dostajemy
        wraz z JDK. Nic nie stoi na przeszkodzie, aby tworzyć własne klasy wyjątków. Wystar-
        czy więc, e napiszemy klasę pochodną pośrednio lub bezpośrednio z klasy 6JTQYCDNG,
        a będziemy mogli wykorzystywać ją do zgłaszania naszych własnych wyjątków. W prak-
        tyce jednak wyjątki wyprowadzamy z klasy 'ZEGRVKQP i klas od niej pochodnych. Klasa
        taka w najprostszej postaci będzie miała postać:
           RWDNKE
           ENCUU PCYCAMNCU[ GZVGPFU 'ZEGRVKQP
           ]
             VTG è MNCU[
           _

        Przykładowo mo emy utworzyć bardzo prostą klasę o nazwie )GPGTCN'ZEGRVKQP
        (wyjątek ogólny) w postaci:
           RWDNKE
           ENCUU )GPGTCN'ZEGRVKQP GZVGPFU 'ZEGRVKQP
           ]
           _

        To w zupełności wystarczy. Nie musimy dodawać adnych nowych pól i metod. Ta
        klasa jest pełnoprawną klasą obsługującą wyjątki, z której mo emy korzystać w taki
        sam sposób, jak ze wszystkich innych klas opisujących wyjątki. Na listingu 4.19 jest
        widoczna przykładowa klasa OCKP, która generuje wyjątek )GPGTCN'ZEGRVKQP.

Listing 4.19.
           RWDNKE
           ENCUU /CKP
           ]
             RWDNKE UVCVKE XQKF OCKP 
5VTKPI CTIU=?
             VJTQYU )GPGTCN'ZEGRVKQP
176                                                                      Praktyczny kurs Java


                ]
                      VJTQY PGY )GPGTCN'ZEGRVKQP

                _
           _


        W metodzie OCKP za pomocą instrukcji VJTQYU zaznaczamy, e metoda ta mo e zgłaszać
        wyjątek klasy )GPGTCN'ZEGRVKQP, sam wyjątek zgłaszamy natomiast przez zastosowanie
        instrukcji VJTQY, dokładnie w taki sam sposób, jak we wcześniejszych przykładach.
        Na rysunku 4.17 jest widoczny efekt działania takiego programu, faktycznie zgłoszony
        został wyjątek nowej klasy: )GPGTCN'ZEGRVKQP.

Rysunek 4.17.
Zgłaszanie własnych
wyjątków




        Własne klasy wyjątków mo na wyprowadzać równie z klas pochodnych od 'ZEGRVKQP.
        Moglibyśmy np. rozszerzyć klasę #TKVJOGVKE'ZEGRVKQP o wyjątek zgłaszany wyłącznie
        wtedy, kiedy wykryjemy dzielenie przez zero. Klasę taką nazwalibyśmy KXKFG$[GTQ
        å'ZEGRVKQP. Miałaby ona postać widoczną na listingu 4.20.

Listing 4.20.
           RWDNKE
           ENCUU KXKFG$[GTQ'ZEGRVKQP GZVGPFU #TKVJOGVKE'ZEGRVKQP
           ]
           _


        Mo emy teraz zmodyfikować program z listingu 4.15 tak, aby po wykryciu dzielenia
        przez zero był zgłaszany wyjątek naszego nowego typu, czyli KXKFG$[GTQ'ZEGRVKQP.
        Klasa taka została przedstawiona na listingu 4.21.

Listing 4.21.
           RWDNKE
           ENCUU 'ZCORNG
           ]
             RWDNKE FQWDNG H
KPV NKEDC KPV NKEDC
             ]
                    KH
NKEDC  
                           VJTQY PGY KXKFG$[GTQ'ZEGRVKQP

                    TGVWTP NKEDC  NKEDC
             _
             RWDNKE UVCVKE XQKF OCKP
5VTKPI CTIU=?
             ]
                    'ZCORNG GZCORNG  PGY 'ZCORNG

                    FQWDNG Y[PKM  GZCORNGH
 
                    5[UVGOQWVRTKPVNP
 9[PKM RKGTYUGIQ FKGNGPKC   
 Y[PKM
Rozdział 4. ♦ Wyjątki                                                                      177


                    Y[PKM  GZCORNGH
 
                    5[UVGOQWVRTKPVNP
 9[PKM FTWIKGIQ FKGNGPKC     
 Y[PKM
                _
           _


        W stosunku do kodu z listingu 4.15 zmiany nie są du e, ograniczają się do zmiany typu
        zgłaszanego wyjątku w metodzie H. Zadaniem tej metody nadal jest zwrócenie wyniku
        dzielenia argumentu NKEDC przez argument NKEDC. W metodzie OCKP dwukrotnie
        wywołujemy metodę H, pierwszy raz z prawidłowymi danymi i drugi raz z danymi,
        które spowodują wygenerowanie wyjątku. Efekt działania przedstawionego kodu jest
        widoczny na rysunku 4.18.

Rysunek 4.18.
Zgłoszenie wyjątku
DivideByZeroException




        Zwróćmy jednak uwagę, e pierwotnie (listing 4.15) przy zgłaszaniu wyjątku para-
        metrem konstruktora był komunikat (czyli wartość typu 5VTKPI). Tym razem nie mo-
        gliśmy jej umieścić, gdy nasza klasa KXKFG$[GTQ'ZEGRVKQP nie posiada konstruktora
        przyjmującego jako parametr obiektu typu 5VTKPI, a jedynie bezparametrowy kon-
        struktor domyślny. Aby zatem mo na było przekazywać nasze własne komunikaty,
        nale y dopisać do klasy KXKFG$[GTQ'ZEGRVKQP odpowiedni konstruktor. Przyjmie ona
        wtedy postać widoczną na listingu 4.22.

Listing 4.22.
           RWDNKE
           ENCUU KXKFG$[GTQ'ZEGRVKQP GZVGPFU #TKVJOGVKE'ZEGRVKQP
           ]
             RWDNKE KXKFG$[GTQ'ZEGRVKQP
5VTKPI UVT
             ]
                    UWRGT
UVT
             _
           _


        Teraz instrukcja VJTQY z listingu 4.21 mogłaby przyjąć np. następującą postać:
           VJTQY PGY KXKFG$[GTQ'ZEGRVKQP
 KGNGPKG RTG GTQ    
 NKEDC 
  
 NKEDC


Sekcja finally
        Do bloku VT[ mo emy dołączyć sekcję HKPCNN[, która będzie wykonana zawsze, nie-
        zale nie od tego, co będzie działo się w bloku VT[. Schematycznie taka konstrukcja
        będzie wyglądała następująco:
178                                                                      Praktyczny kurs Java


           VT[]
             KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM
           _
           ECVEJ
]
             KPUVTWMELG UGMELK ECVEJ
           _
           HKPCNN[]
             KPUVTWMELG UGMELK HKPCNN[
           _

        Zgodnie z tym, co zostało napisane wcześniej, instrukcje sekcji HKPCNN[ są wykonywane
        zawsze, niezale nie od tego, czy w bloku VT[ wystąpi wyjątek, czy nie. Obrazuje to
        przykład z listingu 4.23, który jest oparty na kodzie z listingów 4.20 i 4.21.

Listing 4.23.
           RWDNKE
           ENCUU 'ZCORNG
           ]
             RWDNKE FQWDNG H
KPV NKEDC KPV NKEDC
             ]
                    KH
NKEDC  
                           VJTQY PGY KXKFG$[GTQ'ZEGRVKQP
 KGNGPKG RTG GTQ   
 NKEDC
                              
  
 NKEDC
                    TGVWTP NKEDC  NKEDC
             _
             RWDNKE UVCVKE XQKF OCKP
5VTKPI CTIU=?
             ]
                    'ZCORNG GZCORNG  PGY 'ZCORNG

                    FQWDNG Y[PKM
                    VT[]
                           Y[PKM  GZCORNGH
 
                    _
                    ECVEJ
KXKFG$[GTQ'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 2TGEJY[EGPKG Y[LæVMW  
                    _
                    HKPCNN[]
                           5[UVGOQWVRTKPVNP
 5GMELC HKPCNN[  
                    _
                    VT[]
                           Y[PKM  GZCORNGH
 
                    _
                    ECVEJ
KXKFG$[GTQ'ZEGRVKQP G]
                           5[UVGOQWVRTKPVNP
 2TGEJY[EGPKG Y[LæVMW  
                    _
                    HKPCNN[]
                           5[UVGOQWVRTKPVNP
 5GMELC HKPCNN[  
                    _

                _
           _


        Jest to znana nam klasa 'ZCORNG z metodą H wykonującą dzielenie przekazanych jej
        argumentów. Tym razem metoda H pozostała bez zmian w stosunku do wersji z listingu
        4.21, czyli zgłasza błąd KXKFG$[GTQ'ZEGRVKQP. Zmodyfikowaliśmy natomiast metodę

More Related Content

What's hot

CorelDRAW 11. Vademecum profesjonalisty. Tom 1
CorelDRAW 11. Vademecum profesjonalisty. Tom 1CorelDRAW 11. Vademecum profesjonalisty. Tom 1
CorelDRAW 11. Vademecum profesjonalisty. Tom 1Wydawnictwo Helion
 
Programowanie obiektowe w Visual Basic .NET dla każdego
Programowanie obiektowe w Visual Basic .NET dla każdegoProgramowanie obiektowe w Visual Basic .NET dla każdego
Programowanie obiektowe w Visual Basic .NET dla każdegoWydawnictwo Helion
 
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i EclipseJava. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i EclipseWydawnictwo Helion
 
CorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneCorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneWydawnictwo Helion
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaWydawnictwo Helion
 
100 sposobów na Visual Studio
100 sposobów na Visual Studio100 sposobów na Visual Studio
100 sposobów na Visual StudioWydawnictwo Helion
 
JavaScript dla każdego. Wydanie IV
JavaScript dla każdego. Wydanie IVJavaScript dla każdego. Wydanie IV
JavaScript dla każdego. Wydanie IVWydawnictwo Helion
 
Język C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaJęzyk C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaWydawnictwo Helion
 
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikAdobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikWydawnictwo Helion
 
Java. Obsługa wyjątków, usuwanie błędów i testowanie kodu
Java. Obsługa wyjątków, usuwanie błędów i testowanie koduJava. Obsługa wyjątków, usuwanie błędów i testowanie kodu
Java. Obsługa wyjątków, usuwanie błędów i testowanie koduWydawnictwo Helion
 
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikAdobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikWydawnictwo Helion
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówWydawnictwo Helion
 

What's hot (20)

JavaScript dla każdego
JavaScript dla każdegoJavaScript dla każdego
JavaScript dla każdego
 
CorelDRAW 11. Vademecum profesjonalisty. Tom 1
CorelDRAW 11. Vademecum profesjonalisty. Tom 1CorelDRAW 11. Vademecum profesjonalisty. Tom 1
CorelDRAW 11. Vademecum profesjonalisty. Tom 1
 
Programowanie obiektowe w Visual Basic .NET dla każdego
Programowanie obiektowe w Visual Basic .NET dla każdegoProgramowanie obiektowe w Visual Basic .NET dla każdego
Programowanie obiektowe w Visual Basic .NET dla każdego
 
Win32ASM. Asembler w Windows
Win32ASM. Asembler w WindowsWin32ASM. Asembler w Windows
Win32ASM. Asembler w Windows
 
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i EclipseJava. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
Java. Tworzenie aplikacji sieciowych za pomocą Springa, Hibernate i Eclipse
 
CorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczneCorelDRAW 11. Ćwiczenia praktyczne
CorelDRAW 11. Ćwiczenia praktyczne
 
Java 2. Podstawy
Java 2. PodstawyJava 2. Podstawy
Java 2. Podstawy
 
Photoshop 7/7 CE. Kurs
Photoshop 7/7 CE. KursPhotoshop 7/7 CE. Kurs
Photoshop 7/7 CE. Kurs
 
Adobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. ĆwiczeniaAdobe Illustrator 10. Ćwiczenia
Adobe Illustrator 10. Ćwiczenia
 
100 sposobów na Visual Studio
100 sposobów na Visual Studio100 sposobów na Visual Studio
100 sposobów na Visual Studio
 
JavaScript dla każdego. Wydanie IV
JavaScript dla każdego. Wydanie IVJavaScript dla każdego. Wydanie IV
JavaScript dla każdego. Wydanie IV
 
Język C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowaniaJęzyk C++. Koncepcje i techniki programowania
Język C++. Koncepcje i techniki programowania
 
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznikAdobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
Adobe Illustrator CS2/CS2 PL. Oficjalny podręcznik
 
ABC Delphi 6
ABC Delphi 6ABC Delphi 6
ABC Delphi 6
 
Java. Wprowadzenie
Java. WprowadzenieJava. Wprowadzenie
Java. Wprowadzenie
 
Po prostu PowerPoint 2007 PL
Po prostu PowerPoint 2007 PLPo prostu PowerPoint 2007 PL
Po prostu PowerPoint 2007 PL
 
Java. Obsługa wyjątków, usuwanie błędów i testowanie kodu
Java. Obsługa wyjątków, usuwanie błędów i testowanie koduJava. Obsługa wyjątków, usuwanie błędów i testowanie kodu
Java. Obsługa wyjątków, usuwanie błędów i testowanie kodu
 
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznikAdobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
Adobe Photoshop CS3/CS3 PL. Oficjalny podręcznik
 
Język C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistówJęzyk C++. Gotowe rozwiązania dla programistów
Język C++. Gotowe rozwiązania dla programistów
 
CorelDraw X3 PL. Kurs
CorelDraw X3 PL. KursCorelDraw X3 PL. Kurs
CorelDraw X3 PL. Kurs
 

Similar to Praktyczny kurs Java

Praktyczny kurs Java. Wydanie II
Praktyczny kurs Java. Wydanie IIPraktyczny kurs Java. Wydanie II
Praktyczny kurs Java. Wydanie IIWydawnictwo Helion
 
Java. Współbieżność dla praktyków
Java. Współbieżność dla praktykówJava. Współbieżność dla praktyków
Java. Współbieżność dla praktykówWydawnictwo Helion
 
PHP5. Zaawansowane programowanie
PHP5. Zaawansowane programowaniePHP5. Zaawansowane programowanie
PHP5. Zaawansowane programowanieWydawnictwo Helion
 
J2EE. Vademecum profesjonalisty. Wydanie II
J2EE. Vademecum profesjonalisty. Wydanie IIJ2EE. Vademecum profesjonalisty. Wydanie II
J2EE. Vademecum profesjonalisty. Wydanie IIWydawnictwo Helion
 
Delphi 2007 dla WIN32 i bazy danych
Delphi 2007 dla WIN32 i bazy danychDelphi 2007 dla WIN32 i bazy danych
Delphi 2007 dla WIN32 i bazy danychWydawnictwo Helion
 
Aplikacje w Delphi. Przykłady. Wydanie II
Aplikacje w Delphi. Przykłady. Wydanie IIAplikacje w Delphi. Przykłady. Wydanie II
Aplikacje w Delphi. Przykłady. Wydanie IIWydawnictwo Helion
 
JavaScript. Zaawansowane programowanie
JavaScript. Zaawansowane programowanieJavaScript. Zaawansowane programowanie
JavaScript. Zaawansowane programowanieWydawnictwo Helion
 
Po prostu PHP. Techniki zaawansowane
Po prostu PHP. Techniki zaawansowanePo prostu PHP. Techniki zaawansowane
Po prostu PHP. Techniki zaawansowaneWydawnictwo Helion
 
.NET Framework 2.0. Zaawansowane programowanie
.NET Framework 2.0. Zaawansowane programowanie.NET Framework 2.0. Zaawansowane programowanie
.NET Framework 2.0. Zaawansowane programowanieWydawnictwo Helion
 
Java. Usługi WWW. Vademecum profesjonalisty
Java. Usługi WWW. Vademecum profesjonalistyJava. Usługi WWW. Vademecum profesjonalisty
Java. Usługi WWW. Vademecum profesjonalistyWydawnictwo Helion
 
Java 2. Techniki zaawansowane. Wydanie II
Java 2. Techniki zaawansowane. Wydanie IIJava 2. Techniki zaawansowane. Wydanie II
Java 2. Techniki zaawansowane. Wydanie IIWydawnictwo Helion
 

Similar to Praktyczny kurs Java (20)

Praktyczny kurs Java. Wydanie II
Praktyczny kurs Java. Wydanie IIPraktyczny kurs Java. Wydanie II
Praktyczny kurs Java. Wydanie II
 
Java. Współbieżność dla praktyków
Java. Współbieżność dla praktykówJava. Współbieżność dla praktyków
Java. Współbieżność dla praktyków
 
PHP5. Zaawansowane programowanie
PHP5. Zaawansowane programowaniePHP5. Zaawansowane programowanie
PHP5. Zaawansowane programowanie
 
Spring. Zapiski programisty
Spring. Zapiski programistySpring. Zapiski programisty
Spring. Zapiski programisty
 
ABC Delphi 2006
ABC Delphi 2006ABC Delphi 2006
ABC Delphi 2006
 
Delphi. Szybki start
Delphi. Szybki startDelphi. Szybki start
Delphi. Szybki start
 
Java. Sztuka programowania
Java. Sztuka programowaniaJava. Sztuka programowania
Java. Sztuka programowania
 
J2EE. Vademecum profesjonalisty. Wydanie II
J2EE. Vademecum profesjonalisty. Wydanie IIJ2EE. Vademecum profesjonalisty. Wydanie II
J2EE. Vademecum profesjonalisty. Wydanie II
 
Java. Rozmówki
Java. RozmówkiJava. Rozmówki
Java. Rozmówki
 
Delphi 2007 dla WIN32 i bazy danych
Delphi 2007 dla WIN32 i bazy danychDelphi 2007 dla WIN32 i bazy danych
Delphi 2007 dla WIN32 i bazy danych
 
Aplikacje w Delphi. Przykłady. Wydanie II
Aplikacje w Delphi. Przykłady. Wydanie IIAplikacje w Delphi. Przykłady. Wydanie II
Aplikacje w Delphi. Przykłady. Wydanie II
 
Visual Basic .NET. Ćwiczenia
Visual Basic .NET. ĆwiczeniaVisual Basic .NET. Ćwiczenia
Visual Basic .NET. Ćwiczenia
 
JavaScript. Zaawansowane programowanie
JavaScript. Zaawansowane programowanieJavaScript. Zaawansowane programowanie
JavaScript. Zaawansowane programowanie
 
Prolog. Programowanie
Prolog. ProgramowanieProlog. Programowanie
Prolog. Programowanie
 
C# i ASP.NET. Szybki start
C# i ASP.NET. Szybki startC# i ASP.NET. Szybki start
C# i ASP.NET. Szybki start
 
eXtreme programming
eXtreme programmingeXtreme programming
eXtreme programming
 
Po prostu PHP. Techniki zaawansowane
Po prostu PHP. Techniki zaawansowanePo prostu PHP. Techniki zaawansowane
Po prostu PHP. Techniki zaawansowane
 
.NET Framework 2.0. Zaawansowane programowanie
.NET Framework 2.0. Zaawansowane programowanie.NET Framework 2.0. Zaawansowane programowanie
.NET Framework 2.0. Zaawansowane programowanie
 
Java. Usługi WWW. Vademecum profesjonalisty
Java. Usługi WWW. Vademecum profesjonalistyJava. Usługi WWW. Vademecum profesjonalisty
Java. Usługi WWW. Vademecum profesjonalisty
 
Java 2. Techniki zaawansowane. Wydanie II
Java 2. Techniki zaawansowane. Wydanie IIJava 2. Techniki zaawansowane. Wydanie II
Java 2. Techniki zaawansowane. Wydanie II
 

More from Wydawnictwo Helion

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyWydawnictwo Helion
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikWydawnictwo Helion
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczneWydawnictwo Helion
 
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesieE-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesieWydawnictwo Helion
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsWydawnictwo Helion
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IIWydawnictwo Helion
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuWydawnictwo Helion
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIWydawnictwo Helion
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningWydawnictwo Helion
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykWydawnictwo Helion
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaWydawnictwo Helion
 

More from Wydawnictwo Helion (20)

Tworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. ProjektyTworzenie filmów w Windows XP. Projekty
Tworzenie filmów w Windows XP. Projekty
 
Blog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnikBlog, więcej niż internetowy pamiętnik
Blog, więcej niż internetowy pamiętnik
 
Access w biurze i nie tylko
Access w biurze i nie tylkoAccess w biurze i nie tylko
Access w biurze i nie tylko
 
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktycznePozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
Pozycjonowanie i optymalizacja stron WWW. Ćwiczenia praktyczne
 
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesieE-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
E-wizerunek. Internet jako narzędzie kreowania image'u w biznesie
 
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla WindowsMicrosoft Visual C++ 2008. Tworzenie aplikacji dla Windows
Microsoft Visual C++ 2008. Tworzenie aplikacji dla Windows
 
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie IICo potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
Co potrafi Twój iPhone? Podręcznik użytkownika. Wydanie II
 
Makrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółuMakrofotografia. Magia szczegółu
Makrofotografia. Magia szczegółu
 
Windows PowerShell. Podstawy
Windows PowerShell. PodstawyWindows PowerShell. Podstawy
Windows PowerShell. Podstawy
 
Java. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie IIJava. Efektywne programowanie. Wydanie II
Java. Efektywne programowanie. Wydanie II
 
JavaScript. Pierwsze starcie
JavaScript. Pierwsze starcieJavaScript. Pierwsze starcie
JavaScript. Pierwsze starcie
 
Ajax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny treningAjax, JavaScript i PHP. Intensywny trening
Ajax, JavaScript i PHP. Intensywny trening
 
PowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktykPowerPoint 2007 PL. Seria praktyk
PowerPoint 2007 PL. Seria praktyk
 
Excel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktykExcel 2007 PL. Seria praktyk
Excel 2007 PL. Seria praktyk
 
Access 2007 PL. Seria praktyk
Access 2007 PL. Seria praktykAccess 2007 PL. Seria praktyk
Access 2007 PL. Seria praktyk
 
Word 2007 PL. Seria praktyk
Word 2007 PL. Seria praktykWord 2007 PL. Seria praktyk
Word 2007 PL. Seria praktyk
 
Serwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacjaSerwisy społecznościowe. Budowa, administracja i moderacja
Serwisy społecznościowe. Budowa, administracja i moderacja
 
AutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PLAutoCAD 2008 i 2008 PL
AutoCAD 2008 i 2008 PL
 
Bazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcieBazy danych. Pierwsze starcie
Bazy danych. Pierwsze starcie
 
Inventor. Pierwsze kroki
Inventor. Pierwsze krokiInventor. Pierwsze kroki
Inventor. Pierwsze kroki
 

Praktyczny kurs Java

  • 1. IDZ DO PRZYK£ADOWY ROZDZIA£ SPIS TRE CI Praktyczny kurs Java Autor: Marcin Lis KATALOG KSI¥¯EK ISBN: 83-7361-395-1 Format: B5, stron: 384 KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK Poznaj tajniki najpopularniejszego DODAJ DO KOSZYKA jêzyka programowania w erze Internetu Chyba wszyscy u¿ytkownicy internetu spotkali siê z Jav¹, czêsto nawet o tym nie wiedz¹c. W ci¹gu ostatnich 10 lat zyska³a ona ogromn¹ popularno æ, szczególnie CENNIK I INFORMACJE w ród programistów aplikacji sieciowych. Jednak¿e kojarzenie jej z jêzykiem przeznaczonym wy³¹cznie do tworzenia takich programów jest du¿ym b³êdem. ZAMÓW INFORMACJE Java to w pe³ni funkcjonalny i doskonale dopracowany jêzyk programowania, O NOWO CIACH nadaj¹cy siê do tworzenia ró¿nych aplikacji, a nie tylko apletów dzia³aj¹cych na stronach internetowych. ZAMÓW CENNIK W Javie pisane s¹ gry sieciowe, systemy bankowo ci elektronicznej, pakiety wspomagaj¹ce sprzeda¿ i obs³ugê klienta, a nawet aplikacje dzia³aj¹ce w telefonach komórkowych i komputerach przeno nych. Podstawow¹ zalet¹ jêzyka Java jest CZYTELNIA przeno no æ kodu -- raz napisany program mo¿na uruchomiæ na ka¿dym urz¹dzeniu, na którym zainstalowane jest odpowiednie rodowisko uruchomieniowe, zwane JRE. FRAGMENTY KSI¥¯EK ONLINE Ksi¹¿ka „Praktyczny kurs Java” przeznaczona jest dla osób rozpoczynaj¹cych swoj¹ przygodê z programowaniem w tym jêzyku. Opisuje podstawy jêzyka, zasady programowania obiektowego i tworzenia w³asnych apletów i aplikacji. Czytaj¹c kolejne rozdzia³y, dowiesz siê: • Jakie typy danych wykorzystywane s¹ w Javie • Jak deklarowaæ zmienne i wyprowadzaæ ich warto ci na ekran • W jaki sposób sterowaæ przebiegiem wykonywania programu • Jakie zasady rz¹dz¹ programowaniem obiektowym • Czym s¹ klasy, obiekty, argumenty i metody • Co to s¹ wyj¹tki i jak je obs³ugiwaæ w programie • Jak wykorzystaæ zaawansowane techniki programowania obiektowego Wydawnictwo Helion w swoich aplikacjach ul. Chopina 6 • W jaki sposób uzyskiwaæ dostêp do systemu plików z poziomu swojej aplikacji 44-100 Gliwice tel. (32)230-98-63 • Jak tworzyæ aplety i samodzielne aplikacje e-mail: helion@helion.pl Zapoznaj siê z podstawami programowania w Javie i naucz siê zasad programowania obiektowego, a tak¿e dowiedz siê, czym s¹ wyj¹tki w Javie i stwórz w³asne aplety i aplikacje.
  • 2. Spis treści Wstęp ............................................................................................... 5 Rozdział 1. Podstawy .......................................................................................... 7 Lekcja 1. Struktura programu, kompilacja i wykonanie...............................................7 Lekcja 2. Podstawy obiektowości i typy danych ..........................................................9 Lekcja 3. Komentarze .................................................................................................12 Rozdział 2. Instrukcje języka ............................................................................. 17 Zmienne.............................................................................................................................17 Lekcja 4. Deklaracje i przypisania..............................................................................18 Lekcja 5. Wyprowadzanie danych na ekran ...............................................................21 Lekcja 6. Operacje na zmiennych...............................................................................27 Instrukcje sterujące............................................................................................................39 Lekcja 7. Instrukcja warunkowa if...else ....................................................................39 Lekcja 8. Instrukcja switch i operator warunkowy.....................................................45 Lekcja 9. Pętle.............................................................................................................49 Lekcja 10. Instrukcje break i continue........................................................................56 Tablice...............................................................................................................................63 Lekcja 11. Podstawowe operacje na tablicach............................................................64 Lekcja 12. Tablice wielowymiarowe..........................................................................68 Rozdział 3. Programowanie obiektowe ............................................................... 79 Podstawy ...........................................................................................................................79 Lekcja 13. Klasy, pola i metody .................................................................................80 Lekcja 14. Argumenty i przecią anie metod ..............................................................87 Lekcja 15. Konstruktory .............................................................................................98 Dziedziczenie ..................................................................................................................110 Lekcja 16. Klasy potomne ........................................................................................110 Lekcja 17. Specyfikatory dostępu i pakiety..............................................................118 Lekcja 18. Przesłanianie metod i składowe statyczne ..............................................132 Lekcja 19. Klasy i składowe i finalne.......................................................................145 Rozdział 4. Wyjątki ......................................................................................... 153 Lekcja 20. Blok try...catch ........................................................................................153 Lekcja 21. Wyjątki to obiekty...................................................................................162 Lekcja 22. Własne wyjątki........................................................................................169
  • 3. 4 Praktyczny kurs Java Rozdział 5. Programowanie obiektowe II .......................................................... 181 Polimorfizm.....................................................................................................................181 Lekcja 23. Konwersje typów i rzutowanie obiektów................................................181 Lekcja 24. Późne wiązanie i wywoływanie metod klas pochodnych .......................190 Lekcja 25. Konstruktory oraz klasy abstrakcyjne.....................................................199 Interfejsy..........................................................................................................................209 Lekcja 26. Tworzenie interfejsów.............................................................................209 Lekcja 27. Wiele interfejsów ....................................................................................216 Klasy wewnętrzne ...........................................................................................................226 Lekcja 28. Klasa w klasie .........................................................................................226 Lekcja 29. Rodzaje klas wewnętrznych i dziedziczenie ...........................................235 Lekcja 30. Klasy anonimowe i zagnie d one...........................................................244 Rozdział 6. System wejścia-wyjścia.................................................................. 253 Lekcja 31. Standardowe wejście...............................................................................253 Lekcja 32. Standardowe wejście i wyjście ...............................................................263 Lekcja 33. System plików.........................................................................................273 Lekcja 34. Operacje na plikach.................................................................................283 Rozdział 7. Aplikacje i aplety ........................................................................... 301 Aplety ..............................................................................................................................301 Lekcja 35. Podstawy apletów ...................................................................................301 Lekcja 36. Czcionki i kolory.....................................................................................310 Lekcja 37. Grafika ....................................................................................................319 Lekcja 38. Dźwięki i obsługa myszy ........................................................................330 Aplikacje .........................................................................................................................340 Lekcja 39. Tworzenie aplikacji.................................................................................340 Lekcja 40. Komponenty............................................................................................359 Skorowidz...................................................................................... 375
  • 4. Rozdział 4. Wyjątki Praktycznie w ka dym większym programie powstają jakieś błędy. Powodów jest bardzo wiele, mo e być to skutek niefrasobliwości programisty, zało enia, e wpro- wadzone dane są zawsze poprawne, niedokładnej specyfikacji poszczególnych modu- łów aplikacji, u ycia niesprawdzonych bibliotek czy nawet zwykłego zapomnienia o zainicjowaniu jednej tylko zmiennej. Na szczęście w Javie, tak jak i w większości współczesnych obiektowych języków programowania, istnieje mechanizm tzw. wyjąt- ków, który pozwala na przechwytywanie błędów. Ta właśnie tematyka zostanie przed- stawiona w kolejnych trzech lekcjach. Lekcja 20. Blok try...catch Lekcja 20. jest poświęcona wprowadzeniu w tematykę wyjątków. Zobaczymy, jakie są sposoby zapobiegania powstawaniu niektórych typów błędów w programach, dowiemy się, jak stosować przechwytujący błędy blok instrukcji VT[ECVEJ. Po- znamy bli ej wyjątek o nieco egzotycznej dla początkujących programistów nazwie #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP, dzięki któremu będziemy mogli uniknąć błędów związanych z przekroczeniem dopuszczalnego zakresu indeksów tablic. Sprawdzanie poprawności danych Powróćmy na chwilę do rozdziału 2. i lekcji 11. Znajdował się tam przykład, w którym następowało odwołanie do nieistniejącego elementu tablicy (listing 2.38). Występowała tam sekwencja instrukcji: KPV VCD=? PGY KPV=? VCD=? Doświadczony programista od razu zauwa y, e instrukcje te są błędne, jako e zade- klarowana została tablica dziesięcioelementowa, więc — poniewa indeksowanie tablicy zaczyna się od zera — ostatni element tablicy ma indeks . Tak więc instrukcja VCD=? powoduje próbę odwołania się do nieistniejącego jedenastego elementu tablicy. Ten błąd jest jednak stosunkowo prosty do wychwycenia, nawet gdyby pomiędzy deklaracją tablicy a nieprawidłowym odwołaniem były umieszczone inne instrukcje.
  • 5. 154 Praktyczny kurs Java Du o więcej kłopotów mogłyby nam sprawić sytuacja, gdyby np. tablica była deklaro- wana w jednej klasie, a odwołanie do niej następowało w innej klasie. Taka przykładowa sytuacja została przedstawiona na listingu 4.1. Listing 4.1. RWDNKE ENCUU 6CDNKEC ] RTKXCVG KPV=? VCDNKEC PGY KPV=? RWDNKE KPV RQDKGT'NGOGPV KPV KPFGMU ] TGVWTP VCDNKEC=KPFGMU? _ RWDNKE XQKF WUVCY'NGOGPV KPV KPFGMU KPV YCTVQUE ] VCDNKEC=KPFGMU? YCTVQUE _ _ RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 6CDNKEC VCDNKEC PGY 6CDNKEC VCDNKECWUVCY'NGOGPV KPV NKEDC VCDNKECRQDKGT'NGOGPV 5[UVGOQWVRTKPVNP NKEDC _ _ Powstały tu dwie klasy: 6CDNKEC oraz /CKP. W klasie 6CDNKEC zostało zadeklarowane prywatne pole typu tablicowego o nazwie VCDNKEC, któremu została przypisana dzie- sięcioelementowa tablica liczb całkowitych. Poniewa pole to jest polem prywatnym (por. lekcja 17.), dostęp do niego mają jedynie inne składowe klasy 6CDNKEC. Dlatego te powstały dwie metody RQDKGT'NGOGPV oraz WUVCY'NGOGPV operujące na elemen- tach tablicy. Metoda RQDKGT'NGOGPV zwraca wartość zapisaną w komórce o indeksie przekazanym jako argument, natomiast WUVCY'NGOGPV zapisuje wartość drugiego argu- mentu w komórce o indeksie wskazywanym przez argument pierwszy. W klasie /CKP tworzymy obiekt klasy 6CDNKEC i wykorzystujemy metodę WUVCY'NGOGPV do zapisania w piątej komórce wartości . W kolejnej linii popełniamy drobny błąd. W metodzie RQDKGT'NGOGPV odwołujemy się do nieistniejącego elementu o indeksie . Musi to spowodować wystąpienie błędu w trakcie działania aplikacji (rysunek 4.1). Błąd tego typu bardzo łatwo popełnić, gdy w klasie /CKP nie widzimy rozmiarów tablicy, nietrudno więc o pomyłkę. Rysunek 4.1. Odwołanie do nieistniejącego elementu w klasie Tablica
  • 6. Rozdział 4. ♦ Wyjątki 155 Jak poradzić sobie z takim problemem? Pierwszym nasuwającym się sposobem jest sprawdzanie w metodach RQDKGT'NGOGPV i WUVCY'NGOGPV, czy przekazane argumenty nie przekraczają dopuszczalnych wartości. Jeśli takie przekroczenie wartości nastąpi, nale y wtedy zasygnalizować błąd. To jednak prowokuje pytanie: w jaki sposób ten błąd sygnalizować? Pomysłem znanym programistom C/C++ jest np. zwracanie przez funkcję (metodę) wartości w przypadku błędu oraz wartości nieujemnej (najczę- ściej zero), jeśli błąd nie wystąpił1. Ta metoda będzie dobra w przypadku metody WUVCY'NGOGPV, która wyglądałaby wtedy następująco: RWDNKE KPV WUVCY'NGOGPV KPV KPFGMU KPV YCTVQUE ] KH KPFGMU VCDNKECNGPIVJ] TGVWTP _ GNUG] VCDNKEC=KPFGMU? YCTVQUE TGVWTP _ _ Wystarczyłoby teraz w klasie /CKP testować wartość zwróconą przez WUVCY'NGOGPV, aby sprawdzić, czy nie przekroczyliśmy dopuszczalnego indeksu tablicy. Niestety, tej techniki nie mo na zastosować w przypadku metody RQDKGT'NGOGPV, przecie zwraca ona wartość zapisaną w jednej z komórek tablicy. Czyli i u yte przed chwilą do zasygnalizowania, czy operacja zakończyła się błędem, mogą być wartościami odczyta- nymi z tablicy. Trzeba zatem wymyślić inny sposób. Mo e być to np. wykorzystanie dodatkowego pola sygnalizującego w klasie 6CDNKEC. Pole to byłoby typu DQQNGCP. Ustawione na VTWG oznaczałoby, e ostatnia operacja na klasie zakończyła się błędem, natomiast ustawione na HCNUG, e ostatnia operacja zakończyła się sukcesem. Klasa 6CDNKEC miałaby wtedy postać, jak na listingu 4.2. Listing 4.2. RWDNKE ENCUU 6CDNKEC ] RTKXCVG KPV=? VCDNKEC PGY KPV=? RWDNKE DQQNGCP Y[UVCRKN$NCF HCNUG RWDNKE KPV RQDKGT'NGOGPV KPV KPFGMU ] KH KPFGMU VCDNKECNGPIVJ] Y[UVCRKN$NCF VTWG TGVWTP _ GNUG] Y[UVCRKN$NCF HCNUG TGVWTP VCDNKEC=KPFGMU? _ _ 1 To tylko przykład. Równie często stosuje się zwrócenie wartości zero jako oznaczenie prawidłowego wykonania funkcji.
  • 7. 156 Praktyczny kurs Java RWDNKE XQKF WUVCY'NGOGPV KPV KPFGMU KPV YCTVQUE ] KH KPFGMU VCDNKECNGPIVJ] Y[UVCRKN$NCF VTWG _ GNUG] VCDNKEC=KPFGMU? YCTVQUE Y[UVCRKN$NCF HCNUG _ _ _ Do klasy dodaliśmy pole typu DQQNGCP o nazwie Y[UVCRKN$NCF. Jego początkowa wartość to HCNUG. W metodzie RQDKGT'NGOGPV sprawdzamy najpierw, czy przekazany indeks nie przekracza dopuszczalnej maksymalnej wartości. Jeśli tak, ustawiamy pole Y[UVCRKN$NCF na VTWG oraz zwracamy wartość zero. Oczywiście, w tym przypadku zwrócona wartość nie ma adnego praktycznego znaczenia (przecie wystąpił błąd), niemniej coś musimy zwrócić. U ycie instrukcji TGVWTP i zwrócenie wartości typu KPV jest bowiem konieczne, inaczej kompilator zgłosi błąd. Jeśli jednak argument przeka- zany metodzie nie przekracza dopuszczalnego indeksu tablicy, pole Y[UVCRKN$NCF ustawiamy na HCNUG oraz zwracamy wartość znajdującą się pod tym indeksem. W metodzie WUVCY'NGOGPV postępujemy podobnie. Sprawdzamy, czy przekazany indeks nie przekracza dopuszczalnej wartości. Jeśli tak, pole Y[UVCRKN$NCF ustawiamy na VTWG, w przeciwnym przypadku dokonujemy przypisania wskazanej komórce tablicy i ustawiamy Y[UVCRKN$NCF na HCNUG. Po takiej modyfikacji obu metod w klasie /CKP mo emy ju bez problemów stwierdzić, czy operacje wykonywane na klasie 6CDNKEC zakończyły się sukcesem. Przykładowe wykorzystanie mo liwości, jakie daje nowe pole, zostało przedstawione na listingu 4.3. Listing 4.3. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 6CDNKEC VCDNKEC PGY 6CDNKEC VCDNKECWUVCY'NGOGPV KPV NKEDC VCDNKECRQDKGT'NGOGPV KH VCDNKECY[UVCRKN$NCF] 5[UVGOQWVRTKPVNP 9[UVæRK D æF _ GNUG] 5[UVGOQWVRTKPVNP NKEDC _ _ _ Podstawowe wykonywane operacje są takie same, jak w przypadku klasy z listingu 4.1. Po pobraniu elementu sprawdzamy jednak, czy operacja ta zakończyła się sukcesem i wyświetlamy odpowiedni komunikat na ekranie. Identyczne sprawdzenie mo na
  • 8. Rozdział 4. ♦ Wyjątki 157 wykonać równie po wywołaniu metody WUVCY'NGOGPV. Wykonanie kodu z listingu 4.3 spowoduje rzecz jasna wyświetlenie napisu 9[UVæRK D æF (rysunek 4.2). Rysunek 4.2. Efekt wykonania programu z listingu 4.3 Sposobów poradzenia sobie z problemem przekroczenia indeksu tablicy mo na by zapewne wymyślić jeszcze kilka. Metody tego typu mają jednak powa ną wadę: programiści mają tendencję do ich… niestosowania. Często mo liwy błąd wydaje się zbyt banalny, aby się nim zajmować, czasami po prostu się zapomina się o sprawdza- niu pewnych warunków. Dodatkowo przedstawione wy ej sposoby, czyli zwracanie wartości sygnalizacyjnej czy dodatkowe zmienne, powodują niepotrzebne rozbudo- wywanie kodu aplikacji, co paradoksalnie mo e prowadzić do powstawania kolejnych błędów, czyli błędów powstałych przez napisanie kodu zajmującego się obsługą błę- dów… W Javie zastosowano więc mechanizm tak zwanych wyjątków, znany na pewno programistom C++ i Object Pascala2. Wyjątki w Javie Wyjątek (ang. exception) jest to byt programistyczny, który powstaje w sytuacji wy- stąpienia błędu. Z powstaniem wyjątku spotkaliśmy się ju w rozdziale 2. w lekcji 11. Był to wyjątek spowodowany przekroczeniem dopuszczalnego zakresu tablicy. Po- ka my go raz jeszcze. Na listingu 4.4 została zaprezentowana odpowiednio spreparo- wana klasa /CKP. Listing 4.4. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] KPV VCD=? PGY KPV=? VCD=? _ _ Deklarujemy tablicę liczb typu KPV o nazwie VCD oraz próbujemy przypisać elementowi o indeksie (czyli wykraczającym poza zakres tablicy) wartość . Jeśli skompilu- jemy i uruchomimy taki program, na ekranie zobaczymy obraz widoczny na rysunku 4.3. Został tu wygenerowany wyjątek o nazwie #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP, czyli wyjątek oznaczający, e indeks tablicy znajduje się poza jej granicami. 2 Sama technika obsługi sytuacji wyjątkowych sięga jednak lat sześćdziesiątych ubiegłego stulecia (czyli wieku XX).
  • 9. 158 Praktyczny kurs Java Rysunek 4.3. Odwołanie do nieistniejącego elementu tablicy spowodowało wygenerowanie wyjątku Oczywiście, gdyby mo liwości wyjątków kończyłyby się na wyświetlaniu informacji na ekranie i przerywaniu działania programu, ich przydatność byłaby mocno ograni- czona. Na szczęście, wygenerowany wyjątek mo na przechwycić i wykonać własny kod obsługi błędu. Do takiego przechwycenia słu y blok instrukcji VT[ECVEJ. W naj- prostszej postaci wygląda on następująco: VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ 6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _ W nawiasach klamrowych występujących po słowie VT[ umieszczamy instrukcję, która mo e spowodować wystąpienie wyjątku. W bloku występującym po ECVEJ umieszczamy kod, który ma zostać wykonany, kiedy wyjątek wystąpi. W przypadku klasy /CKP z listingu 4.4 blok VT[ECVEJ nale ałoby zastosować sposób przedsta- wiony na listingu 4.5. Listing 4.5. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] KPV VCD=? PGY KPV=? VT[] VCD=? _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 0KGRTCYKF QY[ KPFGMU VCDNKE[ _ _ _ Jak widać, wszystko odbywa się tu zgodnie z wcześniejszym ogólnym opisem. W bloku VT[ znalazła się instrukcja VCD=? , która — jak wiemy — spowoduje wygene- rowanie wyjątku. W nawiasach okrągłych występujących po instrukcji ECVEJ został wymieniony rodzaj wyjątku, który zostanie wygenerowany: #TTC[+PFGZ1WV1H$QWPFU 3 å'ZEGRVKQP, oraz jego identyfikator: G. Identyfikator to nazwa , która pozwala na wykonywanie operacji związanych z wyjątkiem, czym jednak zajmiemy się w kolejnej 3 Dokładniej jest to nazwa zmiennej obiektowej, wyjaśnimy to bli ej w lekcji 21.
  • 10. Rozdział 4. ♦ Wyjątki 159 lekcji. W bloku po ECVEJ znajduje się instrukcja 5[UVGOQWVRTKPVNP wyświetlająca odpowiedni komunikat na ekranie. Tym razem po uruchomieniu kodu zobaczmy widok zaprezentowany na rysunku 4.4. Rysunek 4.4. Wyjątek został przechwycony w bloku try…catch Blok VT[ECVEJ nie musi jednak obejmować tylko jednej instrukcji ani te tylko in- strukcji mogących wygenerować wyjątek. Przypomnijmy ponownie listing 2.38. Blok VT[ mógłby w tym wypadku objąć wszystkie trzy instrukcje, czyli klasa /CKP miałaby wtedy postać jak na listingu 4.6. Listing 4.6. ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VT[] KPV VCD=? PGY KPV=? VCD=? 5[UVGOQWVRTKPVNP KGUKæV[ GNGOGPV VCDNKE[ OC YCTVQ è VCD=? _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 0KGRTCYKF QY[ KPFGMU VCDNKE[ _ _ _ Nie istnieje równie konieczność obejmowania blokiem VT[ instrukcji bezpośrednio generujących wyjątek, tak jak miało to miejsce w dotychczasowych przykładach. Wyjątek wygenerowany przez obiekt klasy ; mo e być bowiem przechwytywany w klasie :, która korzysta z obiektów klasy ;. Poka emy to na przykładzie klas z listingu 4.1. Klasa 6CDNKEC pozostanie bez zmian, natomiast klasę /CKP zmodyfikujemy tak, aby miała wygląd zaprezentowany na listingu 4.7. Listing 4.7. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 6CDNKEC VCDNKEC PGY 6CDNKEC VT[] VCDNKECWUVCY'NGOGPV KPV NKEDC VCDNKECRQDKGT'NGOGPV 5[UVGOQWVRTKPVNP NKEDC _
  • 11. 160 Praktyczny kurs Java ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 0KGRTCYKF QY[ KPFGMU VCDNKE[ _ _ _ Spójrzmy, w bloku VT[ wykonujemy trzy instrukcje, z których jedna: KPV NKEDC VCDNKECRQDKGT'NGOGPV jest odpowiedzialna za wygenerowanie wyjątku. Wyją- tek jest przecie jednak generowany w ciele metody RQDKGT'NGOGPV klasy 6CDNKEC, a nie w klasie /CKP! Zostanie on jednak przekazany klasie /CKP, jako e wywołuje ona metodę klasy 6CDNKEC. Tym samym w klasie /CKP mo emy zastosować blok VT[ECVEJ. Z identyczną sytuacją będziemy mieli do czynienia w przypadku hierarchicznego wywołania metod jednej klasy. Czyli w sytuacji, kiedy metoda H wywołuje metodę I, która wywołuje metodę J, która z kolei generuje wyjątek. W ka dej z wymienionych metod mo na zastosować blok VT[ECVEJ do przechwycenia tego wyjątku. Dokładnie taki przykład jest widoczny na listingu 4.8. Listing 4.8. RWDNKE ENCUU 'ZCORNG ] RWDNKE XQKF H ] VT[] I _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC H _ _ RWDNKE XQKF I ] VT[] J _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC I _ _ RWDNKE XQKF J ] KPV=? VCD PGY KPV=? VT[] VCD=? _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC J _ _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZ PGY 'ZCORNG
  • 12. Rozdział 4. ♦ Wyjątki 161 VT[] GZH _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC OCKP _ _ _ Taką klasę skompilujemy bez adnych problemów. Musimy jednak dobrze zdawać sobie sprawę, jak taki kod będzie wykonywany. Pytanie bowiem brzmi: które bloki VT[ zostaną wykonane? Zasada jest następująca: zostanie wykonany blok najbli szy instrukcji powodującej wyjątek. Czyli w przypadku przedstawionym na listingu 4.8 jedynie blok obejmujący wywołanie metody VCD=? w metodzie J. Jeśli jednak będziemy usuwać kolejne bloki VT[ najpierw z instrukcji J, następnie I, H i ostatecznie z OCKP, zobaczymy, e faktycznie wykonywany jest zawsze blok najbli szy miejsca wystąpienia błędu. Po usunięciu wszystkich instrukcji VT[ wyjątek nie zostanie obsłu- ony w naszej klasie i obsłu y go maszyna wirtualna Javy, co zaowocuje znanym nam ju komunikatem na konsoli. Zwróćmy jednak uwagę, e w tym wypadku zostanie wy- świetlona cała hierarchia metod, w których był propagowany wyjątek (rysunek 4.5). Rysunek 4.5. Przy hierarchicznym wywołaniu metod po wystąpieniu wyjątku otrzymamy ich nazwy Ćwiczenia do samodzielnego wykonania 20.1. Popraw kod klasy z listingu 4.2 tak, aby w metodach RQDKGT'NGOGPV i WUVCY'NGOGPV było równie sprawdzane, czy przekazany indeks nie przekracza minimalnej dopusz- czalnej wartości. 20.2. Zmień kod klasy /CKP z listingu 4.3 w taki sposób, aby było równie sprawdzane, czy wywołanie metody WUVCY'NGOGPV zakończyło się sukcesem. 20.3. Popraw kod z listingu 4.2 tak, aby do wychwytywania błędów był wykorzysty- wany mechanizm wyjątków zamiast instrukcji warunkowej KH. 20.4. Napisz klasę 'ZCORNG, w której będzie się znajdowała metoda o nazwie C, która z kolei będzie wywoływała metodę o nazwie D. W metodzie C wygeneruj wyjątek #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP. Napisz następnie klasę /CKP zawierającą metodę OCKP, w której zostanie utworzony obiekt klasy 'ZCORNG i zostaną wywołane metody C oraz D tego obiektu. W metodzie OCKP zastosuj bloki VT[ECVEJ, przechwytujące powstały wyjątek.
  • 13. 162 Praktyczny kurs Java Lekcja 21. Wyjątki to obiekty W lekcji 20. poznaliśmy wyjątek sygnalizujący przekroczenie dopuszczalnego zakresu tablicy. To oczywiście nie jedyny dostępny wyjątek, czas poznać równie inne ich typy. W lekcji 21. dowiemy się więc, e wyjątki są tak naprawdę obiektami, a tak e, e tworzą one hierarchiczną strukturę. Poka emy, jak przechwytywać wiele wyjątków w jednym bloku VT[ oraz udowodnimy, e bloki VT[ECVEJ mogą być zagnie d ane. Oka e się, e jeden wyjątek ogólny mo e obsłu yć wiele błędnych sytuacji. Dzielenie przez zero Rodzajów wyjątków jest bardzo wiele. Wiemy ju , jak reagować na przekroczenie zakresu tablicy. Poznajmy zatem inny typ wyjątku, powstający, kiedy zostanie podjęta próba wykonania nielegalnego dzielenia przez zero. W tym celu musimy spreparować odpowiedni fragment kodu. Wystarczy, e w metodzie OCKP umieścimy przykładową instrukcję: KPV NKEDC . Kompilacja takiego kodu przebiegnie bez problemu, jednak próba wykonania musi skończyć się komunikatem o błędzie, widocznym na rysunku 4.6. Widzimy wyraźnie, e tym razem został zgłoszony wyjątek #TKVJOGVKE'ZEGRVKQP (wyjątek arytmetyczny). Rysunek 4.6. Próba wykonania dzielenia przez zero Wykorzystując wiedzę z lekcji 20., nie powinniśmy mieć adnych problemów z napi- saniem kodu, który taki wyjątek przechwyci. Trzeba wykorzystać dobrze nam znaną instrukcję VT[ECVEJ w postaci: VT[] KPV NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] KPUVTWMELG FQ Y[MQPCPKC MKGF[ Y[UVæRK Y[LæVGM _ Intuicja podpowiada nam ju zapewne, e rodzajów wyjątków mo e być bardzo, bardzo du o. I faktycznie tak jest, w klasach dostarczonych w JDK (w wersji SE) jest ich zdefiniowanych blisko 300. Aby sprawnie się nimi posługiwać, musimy dowiedzieć się, czym tak naprawdę są wyjątki. Wyjątek jest obiektem Wyjątek, który określaliśmy jako byt programistyczny, to nic innego jak obiekt, który powstaje, kiedy w programie wystąpi sytuacja wyjątkowa. Skoro wyjątek jest
  • 14. Rozdział 4. ♦ Wyjątki 163 obiektem, to wspominany wcześniej typ wyjątku (#TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP, #TKVJOGVKE'ZEGRVKQP) to nic innego jak klasa opisująca ten e obiekt. Jeśli teraz spoj- rzymy ponownie na ogólną postać instrukcji VT[ECVEJ: VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ 6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _ jasnym stanie się, e w takim razie KFGPV[HKMCVQT9[LæVMW to zmienna obiektowa, wska- zująca na obiekt wyjątku. Na tym obiekcie mo emy wykonywać operacje zdefiniowane w klasie wyjątku. Mo emy np. uzyskać systemowy komunikat o błędzie. Wystarczy wywołać metodę IGV/GUUCIG . Zobaczmy to na przykładzie wyjątku generowanego podczas próby wykonania dzielenia przez zero. Jest on zaprezentowany na listingu 4.9. Listing 4.9. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VT[] KPV NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[UVCRK Y[LæVGM CT[VOGV[EP[ 5[UVGOQWVRTKPVNP -QOWPKMCV U[UVGOQY[ 5[UVGOQWVRTKPVNP GIGV/GUUCIG _ _ _ Wykonujemy tutaj próbę niedozwolonego dzielenia przez zero oraz przechwytujemy wyjątek klasy #TKVJOGVKE'ZEGRVKQP. W bloku ECVEJ najpierw wyświetlamy nasze własne komunikaty o błędzie, a następnie komunikat systemowy. Po uruchomieniu kodu na ekranie zobaczymy widok zaprezentowany na rysunku 4.7. Rysunek 4.7. Wyświetlenie systemowego komunikatu obłędzie Istnieje jeszcze jedna mo liwość uzyskania komunikatu o wyjątku, mianowicie umiesz- czenie w argumencie instrukcji 5[UVGOQWVRTKPVNP zmiennej wskazującej na obiekt wyjątku, czyli w przypadku listingu 4.9: 5[UVGOQWVRTKPVNP G
  • 15. 164 Praktyczny kurs Java W pierwszej chwili mo e się to wydawać nieco dziwne, bo niby skąd instrukcja 5[UVGOQWVRTKPVNP ma wiedzieć, co w takiej sytuacji wyświetlić? Zauwa my jednak, e jest to sytuacja analogiczna, jak w przypadku typów prostych (por. lekcja 5.). Skoro udawało się automatycznie przekształcać np. zmienną typu KPV na ciąg znaków, uda się równie przekształcić zmienną typu obiektowego. Bli ej tym problemem zajmiemy się w rozdziale piątym. Jeśli teraz z programie z listingu 4.9 zamienimy instrukcję: 5[UVGOQWVRTKPVNP GIGV/GUUCIG na: 5[UVGOQWVRTKPVNP G otrzymamy nieco dokładniejszy komunikat określający dodatkowo klasę wyjątku, tak jak jest to widoczne na rysunku 4.8. Rysunek 4.8. Pełniejszy komunikat o typie wyjątku Hierarchia wyjątków Ka dy wyjątek jest obiektem pewnej klasy. Klasy podlegają z kolei regułom dziedzi- czenia, zgodnie z którymi powstaje hierarchia klas. Kiedy zatem pracujemy z wyjątkami, musimy tę kwestię wziąć pod uwagę. Wszystkie standardowe wyjątki, które mo emy przechwytywać w naszych aplikacjach za pomocą bloku VT[ECVEJ, dziedziczą z klasy 'ZEGRVKQP, która z kolei dziedziczy z 6JTQYCDNG oraz 1DLGEV. Hierarchia klas dla wyjątku #TKVJOGVKE'ZEGRVKQP, który wykorzystywaliśmy we wcześniejszych przykładach, jest zaprezentowana na rysunku 4.9. Rysunek 4.9. Hierarchia klas dla wyjątku ArithmeticException Wynika z tego kilka własności. Przede wszystkim, jeśli spodziewamy się, e dana instrukcja mo e wygenerować wyjątek typu :, mo emy zawsze przechwycić wyjątek ogólniejszy, czyli wyjątek, którego typem będzie jedna z klas nadrzędnych do :. Jest to bardzo wygodna technika. Przykładowo z klasy 4WPVKOG'ZEGRVKQP dziedziczy bar- dzo wiele klas wyjątków odpowiadających najró niejszym błędom. Jedną z nich jest #TKVJOGVKE'ZEGRVKQP. Jeśli instrukcje, które obejmujemy blokiem VT[ECVEJ, mogą
  • 16. Rozdział 4. ♦ Wyjątki 165 spowodować wiele ró nych wyjątków, zamiast stosować wiele oddzielnych instrukcji przechwytujących konkretne typy błędów, często lepiej jest zastosować jedną prze- chwytującą wyjątek bardziej ogólny. Spójrzmy na listing 4.10. Listing 4.10. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VT[] KPV NKEDC _ ECVEJ 4WPVKOG'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[UVCRK Y[LæVGM ECUW Y[MQPCPKC 5[UVGOQWVRTKPVNP -QOWPKMCV U[UVGOQY[ 5[UVGOQWVRTKPVNP G _ _ _ Jest to znany nam ju program, generujący błąd polegający na próbie wykonania niedozwolonego dzielenia przez zero. Tym razem jednak zamiast wyjątku klasy #TKVJOGVKE'ZEGRVKQP przechwytujemy wyjątek klasy nadrzędnej 4WPVKOG'ZEGRVKQP. Co więcej, nic nie stoi na przeszkodzie, aby przechwycić wyjątek jeszcze ogólniejszy, czyli wyjątek klasy nadrzędnej do 4WPVKOG'ZEGRVKQP. Jak widać na rysunku 4.9, byłaby to klasa 'ZEGRVKQP. Przechwytywanie wielu wyjątków W jednym bloku VT[ECVEJ mo na przechwytywać wiele wyjątków. Konstrukcja taka zawiera wtedy jeden blok VT[ i wiele bloków ECVEJ. Schematycznie wygląda ona następująco: VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ -NCUC9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _ ECVEJ -NCUC9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _
  • 18. ECVEJ -NCUC9[LæVMW P KFGPV[HKMCVQT9[LæVMWP] QDU WIC Y[LæVMW P _ Po wygenerowaniu wyjątku jest sprawdzane, czy jest on klasy -NCUC9[LCVMW, jeśli tak — są wykonywane instrukcje obsługi tego wyjątku i blok VT[ECVEJ jest opuszczany. Je eli jednak wyjątek nie jest klasy -NCUC9[LCVMW, jest sprawdzane, czy jest on klasy -NCUC9[LæVMW itd.
  • 19. 166 Praktyczny kurs Java Przy tego typu konstrukcjach nale y jednak pamiętać o hierarchii wyjątków, nie jest bowiem obojętne, w jakiej kolejności będą one przechwytywane. Ogólna zasada jest taka, e nie ma znaczenia kolejność, o ile wszystkie wyjątki są na jednym poziomie hierarchii. Jeśli jednak przechwytujemy wyjątki z ró nych poziomów, najpierw muszą to być wyjątki bardziej szczegółowe, czyli stojące ni ej w hierarchii, a dopiero po nich wyjątki bardziej ogólne, czyli stojące wy ej w hierarchii. Nie mo na zatem najpierw przechwycić wyjątku 4WPVKOG'ZEGRVKQP, a dopiero nim wyjątku #TKVJOGVKE'ZEGRVKQP (por. rysunek 4.9), gdy skończy się to błędem kompi- lacji. Jeśli więc dokonamy próby kompilacji przykładowego programu przedstawionego na listingu 4.11, efektem będą komunikaty widoczne na rysunku 4.10. Listing 4.11. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VT[] KPV NKEDC _ ECVEJ 4WPVKOG'ZEGRVKQP G] 5[UVGOQWVRTKPVNP G _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP G _ _ _ Rysunek 4.10. Błędna hierarchia wyjątków powoduje błąd kompilacji Dzieje się tak dlatego, e (mo na powiedzieć) błąd bardziej ogólny zawiera ju w sobie błąd bardziej szczegółowy. Jeśli zatem przechwytujemy najpierw wyjątek 4WPVKOG'ZEGRVKQP, to tak jak byśmy przechwycili ju wyjątki wszystkich klas dziedzi- czących z 4WPVKOG'ZEGRVKQP. Dlatego te kompilator protestuje. Kiedy jednak mo e przydać się sytuacja, e najpierw przechwytujemy wyjątek szcze- gółowy, a potem dopiero ogólny? Otó , wtedy, kiedy chcemy w specyficzny sposób zareagować na konkretny typ wyjątku, a wszystkie pozostałe z danego poziomu hie- rarchii obsłu yć w identyczny, standardowy sposób. Taka przykładowa sytuacja jest przedstawiona na listingu 4.12.
  • 20. Rozdział 4. ♦ Wyjątki 167 Listing 4.12. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 2WPMV RWPMV PWNN KPV NKEDC VT[] NKEDC RWPMVZ NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC 5[UVGOQWVRTKPVNP G _ ECVEJ 'ZEGRVKQP G] 5[UVGOQWVRTKPVNP $ æF QIÎNP[ 5[UVGOQWVRTKPVNP G _ _ _ Zostały zadeklarowane dwie zmienne: pierwsza typu 2WPMV o nazwie RWPMV oraz druga typu KPV o nazwie NKEDC. Zmiennej RWPMV została przypisana wartość pusta PWNN, nie został zatem utworzony aden obiekt klasy 2WPMV. W bloku VT[ są wykonywane dwie błędne instrukcje. Pierwsza z nich to znane nam z poprzednich przykładów dzielenie przez zero. Druga instrukcja z bloku VT[ to z kolei próba odwołania się do pola Z nie- istniejącego obiektu klasy 2WPMV (przecie zmienna RWPMV zawiera wartość PWNN). Ponie- wa chcemy w sposób niestandardowy zareagować na błąd arytmetyczny, najpierw przechwytujemy błąd typu #TKVJOGVKE'ZEGRVKQP i, w przypadku kiedy wystąpi, wyświe- tlamy na ekranie napis 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC. W drugim bloku ECVEJ przechwytujemy wszystkie inne mo liwe wyjątki, w tym tak e wyjątek 0WNN2QKPVGT å'ZEGRVKQP występujący, kiedy próbujemy wykonać operacje na zmiennej obiektowej, która zawiera wartość PWNN. Po uruchomieniu kodu z listingu 4.12 na ekranie pojawi się zgłoszenie tylko pierwszego błędu. Dzieje się tak dlatego, e po jego wystąpieniu blok VT[ został przerwany, a ste- rowanie zostało przekazane blokowi ECVEJ. Czyli jeśli w bloku VT[ któraś z instrukcji spowoduje wygenerowanie wyjątku, dalsze instrukcje z bloku VT[ nie zostaną wykonane. Nie miała więc szansy zostać wykonana nieprawidłowa instrukcja RWPMVZ NKEDC. Jeśli jednak usuniemy wcześniejsze dzielenie przez zero, przekonamy się, e i ten błąd zostanie przechwycony przez drugi blok ECVEJ, a na ekranie pojawi się stosowny komu- nikat (rysunek 4.11). Rysunek 4.11. Odwołanie do pustej zmiennej obiektowej zostało wychwycone przez drugi blok catch
  • 21. 168 Praktyczny kurs Java Zagnieżdżanie bloków try...catch Bloki VT[ECVEJ mo na zagnie d ać. To znaczy, e w jednym bloku przechwytują- cym wyjątek : mo e istnieć drugi blok, który będzie przechwytywał wyjątek ;. Sche- matycznie taka konstrukcja wygląda następująco: VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ 6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _ _ ECVEJ 6[R9[LæVMW KFGPV[HKMCVQT9[LæVMW] QDU WIC Y[LæVMW _ Zagnie d enie takie mo e być wielopoziomowe, czyli w ju zagnie d onym bloku VT[ mo na umieścić kolejny blok VT[, choć w praktyce takich piętrowych konstrukcji zazwyczaj się nie stosuje. Zwykle nie ma takiej potrzeby. Maksymalny poziom takiego bezpośredniego zagnie d enia z reguły nie przekracza dwóch poziomów. Aby na prak- tycznym przykładzie pokazać taką dwupoziomową konstrukcję, zmodyfikujemy przy- kład z listingu 4.12. Zamiast obejmowania jednym blokiem VT[ dwóch instrukcji powo- dujących błąd, zastosujemy zagnie d enie, tak jak jest to widoczne na listingu 4.13. Listing 4.13. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 2WPMV RWPMV PWNN KPV NKEDC VT[] VT[] NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 0KGRTCYKF QYC QRGTCELC CT[VOGV[EPC 5[UVGOQWVRTKPVNP 2T[RKUWLú OKGPPGLNKEDC YCTVQ è NKEDC _ RWPMVZ NKEDC _ ECVEJ 'ZEGRVKQP G] 5[UVGOQWVRTKPVNP $ æF QIÎNP[ 5[UVGOQWVRTKPVNP G _ _ _
  • 22. Rozdział 4. ♦ Wyjątki 169 Podobnie jak w poprzednim przypadku, deklarujemy dwie zmienne: RWPMV klasy 2WPMV oraz NKEDC typu KPV. Zmiennej RWPMV przypisujemy wartość pustą PWNN. W wewnętrznym bloku VT[ próbujemy wykonać nieprawidłowe dzielenie przez zero i przechwytujemy wyjątek #TKVJOGVKE'ZEGRVKQP. Jeśli on wystąpi, zmienna NKEDC otrzymuje domyślną wartość równą , dzięki czemu mo na wykonać kolejną operację, czyli próbę przypi- sania polu Z obiektu RWPMV wartości zmiennej NKEDC. Rzecz jasna, przypisanie takie nie mo e zostać wykonane, gdy zmienna RWPMV jest pusta, jest zatem generowany wyjątek 0WNN2QKPVGT'ZEGRVKQP, który jest przechwytywany przez zewnętrzny blok VT[. Widać więc, e zagnie d anie bloków VT[ mo e być przydatne, choć warto zauwa yć, e identyczny efekt mo na osiągnąć, korzystając równie z niezagnie d onej postaci instrukcji VT[ECVEJ (por. ćwiczenie 21.3). Ćwiczenia do samodzielnego wykonania 21.1. Popraw kod z listingu 4.11 tak, aby przechwytywanie wyjątków odbywało się w prawidłowej kolejności. 21.2. Zmodyfikuj kod z listingu 4.12 tak, aby zostały zgłoszone oba typy błędów: #TKVJOGVKE'ZEGRVKQP oraz 0WNN2QKPVGT'ZEGRVKQP. 21.3. Zmodyfikuj kod z listingu 4.5 w taki sposób, aby usunąć zagnie d enie bloków VT[ECVEJ, nie zmieniając jednak efektów działania programu. Lekcja 22. Własne wyjątki Wyjątki mo emy przechwytywać, aby zapobiec niekontrolowanemu zakończeniu programu w przypadku wystąpienia błędu. Tą technikę poznaliśmy w lekcjach 20. i 21. Okazuje się jednak, e mo na je równie samemu zgłaszać, a tak e e mo na tworzyć nowe, nieistniejące wcześniej klasy wyjątków. Tej właśnie tematyce jest poświęcona bie ąca, 22., lekcja. Zgłoś wyjątek Wiemy, e wyjątki są obiektami. Skoro tak, zgłoszenie własnego wyjątku będzie po- legało po prostu na utworzeniu nowego obiektu klasy opisującej wyjątek. Dokładniej za pomocą instrukcji PGY nale y utworzyć nowy obiekt klasy, która pośrednio lub bezpo- średnio dziedziczy z klasy 6JTQYCDNG. W najbardziej ogólnym przypadku będzie to klasa 'ZEGRVKQP. Tak utworzony obiekt musi stać się parametrem instrukcji VJTQY. Jeśli zatem gdziekolwiek w pisanym przez nas kodzie chcemy zgłosić wyjątek ogólny, wystarczy, e napiszemy: VJTQY PGY 'ZEGRVKQP W specyfikacji metody musimy jednak zaznaczyć, e będziemy w niej zgłaszać wyjątek danej klasy. Robimy to za pomocą instrukcji VJTQYU, w ogólnej postaci: URGE[HKMCVQTAFQUVGRW =UVCVKE? =HKPCN? V[RAYCTCECP[ PCYCAOGVQF[ CTIWOGPV[ VJTQYU -NCUC9[LæVMW -NCUC9[LæVMW -NCUC9[LCVMWP ] VTG è OGVQF[ _
  • 23. 170 Praktyczny kurs Java Zobaczmy, jak to wygląda w praktyce. Załó my, e mamy klasę /CKP, a w niej metodę OCKP. Jedynym zadaniem tej metody będzie zgłoszenie wyjątku klasy 'ZEGRVKQP. Klasa taka jest widoczna na listingu 4.14. Listing 4.14. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? VJTQYU 'ZEGRVKQP ] VJTQY PGY 'ZEGRVKQP _ _ W deklaracji metody OCKP zaznaczyliśmy, e mo e ona generować wyjątek klasy 'ZEGRVKQP poprzez u ycie instrukcji VJTQYU 'ZEGRVKQP. W ciele metody OCKP została natomiast wykorzystana instrukcja VJTQY, która jako parametr otrzymała nowy obiekt klasy 'ZEGRVKQP. Po uruchomieniu takiego programu na ekranie zobaczymy widok zaprezentowany na rysunku 4.12. Jest to najlepszy dowód, e faktycznie udało nam się zgłosić wyjątek. Rysunek 4.12. Zgłoszenie wyjątku klasy Exception Utworzenie obiektu wyjątku nie musi mieć miejsca bezpośrednio w instrukcji VJTQY, mo na utworzyć go wcześniej, przypisać zmiennej obiektowej i dopiero tę zmienną wykorzystać jako parametr dla VJTQY. Czyli zamiast pisać: VJTQY PGY 'ZEGRVKQP mo emy równie dobrze zastosować konstrukcję: 'ZEGRVKQP GZEGRVKQP PGY 'ZEGRVKQP VJTQY GZEGRVKQP W obu przedstawionych przypadkach efekt będzie identyczny, najczęściej korzystamy jednak z pierwszego zaprezentowanego sposobu. Jeśli chcemy, aby zgłaszany wyjątek otrzymał komunikat, nale y przekazać go jako parametr konstruktora klasy 'ZEGRVKQP, czyli napiszemy wtedy: VJTQY PGY 'ZEGRVKQP MQOWPKMCV lub: 'ZEGRVKQP GZEGRVKQP PGY 'ZEGRVKQP MQOWPKMCV VJTQY GZEGRVKQP
  • 24. Rozdział 4. ♦ Wyjątki 171 Oczywiście, mo na tworzyć obiekty wyjątków klas dziedziczących z 'ZEGRVKQP. Przykładowo: jeśli sami wykryjemy próbę dzielenia przez zero, być mo e zechcemy wygenerować nasz wyjątek, nie czekając, a zgłosi go maszyna wirtualna. Spójrzmy na listing 4.15. Listing 4.15. RWDNKE ENCUU 'ZCORNG ] RWDNKE FQWDNG H KPV NKEDC KPV NKEDC ] KH NKEDC VJTQY PGY #TKVJOGVKE'ZEGRVKQP KGNGPKG RTG GTQ NKEDC NKEDC TGVWTP NKEDC NKEDC _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZCORNG PGY 'ZCORNG KPV Y[PKM GZCORNGH 5[UVGOQWVRTKPVNP 9[PKM RKGTYUGIQ FKGNGPKC Y[PKM Y[PKM GZCORNGH 5[UVGOQWVRTKPVNP 9[PKM FTWIKGIQ FKGNGPKC Y[PKM _ _ W klasie 'ZCORNG jest zdefiniowana metoda H, która przyjmuje dwa argumenty typu KPV. Ma ona zwracać wynik dzielenia wartości przekazanej w argumencie NKEDC przez wartość przekazaną w argumencie NKEDC. Jest zatem jasne, e NKEDC nie mo e mieć wartości zero. Sprawdzamy to, wykorzystując instrukcję warunkową KH. Jeśli oka e się, e NKEDC ma jednak wartość zero, za pomocą instrukcji VJTQY wyrzucamy nowy wyjątek klasy #TKVJOGVKE'ZEGRVKQP. W konstruktorze klasy przekazujemy komunikat informujący o dzieleniu przez zero. Podajemy w nim wartości argumentów metody H, tak by łatwo mo na było stwierdzić, jakie parametry spowodowały błąd. W celu przetestowania działania metody H w klasie 'ZCORNG pojawiła się równie metoda OCKP. Tworzymy w niej nowy obiekt klasy 'ZCORNG i przypisujemy go zmiennej o nazwie GZCORNG. Następnie dwukrotnie wywołujemy metodę H, raz przekazując jej argumenty równe i , drugi raz przekazując jej argumenty równe i . Spodziewamy się, e w drugim przypadku program zgłosi wyjątek #TKVJOGVKE'ZEGRVKQP ze zdefiniowanym przez nas komunikatem. Faktycznie program zachowa się w taki właśnie sposób, co jest widoczne na rysunku 4.13. Rysunek 4.13. Zgłoszenie własnego wyjątku klasy ArithmeticException
  • 25. 172 Praktyczny kurs Java Ponowne zgłoszenie przechwyconego wyjątku Wiemy ju , jak przechwytywać wyjątki oraz jak samemu zgłaszać wystąpienie wyjątku. To pozwoli nam zapoznać się z techniką ponownego zgłaszania (potocznie: wyrzuca- nia) ju przechwyconego wyjątku. Jak pamiętamy, bloki VT[ECVEJ mo na zagnie - d ać bezpośrednio, a tak e stosować je w przypadku kaskadowo wywoływanych metod. Jeśli jednak na którymkolwiek poziomie przechwytywaliśmy wyjątek, jego obsługa ulegała zakończeniu. Nie zawsze jest to korzystne zachowanie, czasami istnieje potrzeba, aby po wykonaniu naszego bloku obsługi wyjątek nie był niszczony, ale przekazywany dalej. Aby osiągnąć takie zachowanie, musimy zastosować instrukcję VJTQY. Schema- tycznie wyglądałoby to następująco: VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ V[R6[LæVMW KFGPV[HKMCVQT9[LæVMW] KPUVTWMELG QDU WIWLæEG U[VWCELú Y[LæVMQYæ VJTQY KPFGV[HKMCVQT9[LæVMW _ Listing 4.16 przedstawia, jak taka sytuacja wygląda w praktyce. W bloku VT[ jest wykonywana niedozwolona instrukcja dzielenia przez zero. W bloku ECVEJ najpierw wyświetlamy na ekranie informację o przechwyceniu wyjątku, a następnie za pomocą instrukcji VJTQY ponownie wyrzucamy (zgłaszamy) przechwycony ju wyjątek. Poniewa w programie nie ma ju innego bloku VT[ECVEJ, który mógłby przechwycić ten wyjątek, zostanie on obsłu ony standardowo przez maszynę wirtualną. Dlatego te na ekranie zobaczymy widok zaprezentowany na rysunku 4.14. Listing 4.16. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VT[] KPV NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 6W Y[LæVGM QUVC RTGEJY[EQP[ VJTQY G _ _ _ Rysunek 4.14. Ponowne zgłoszenie raz przechwyconego wyjątku
  • 26. Rozdział 4. ♦ Wyjątki 173 W przypadku zagnie d onych bloków VT[ sytuacja wygląda analogicznie. Wyjątek przechwycony w bloku wewnętrznym i ponownie zgłoszony mo e być obsłu ony w bloku zewnętrznym, w którym mo e być oczywiście zgłoszony kolejny raz itd. Jest to zobrazowane na listingu 4.17. Listing 4.17. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] VW FQYQNPG KPUVTWMELG VT[] VW FQYQNPG KPUVTWMELG VT[] KPV NKEDC _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 6W Y[LæVGM QUVC RTGEJY[EQP[ RKGTYU[ TC VJTQY G _ _ ECVEJ #TKVJOGVKE'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 6W Y[LæVGM QUVC RTGEJY[EQP[ FTWIK TC VJTQY G _ _ _ Mamy tu dwa zagnie d one bloki VT[. W bloku wewnętrznym zostaje wykonana nie- prawidłowa instrukcja dzielenia przez zero. Zostaje ona w tym bloku przechwycona, a na ekranie zostaje wyświetlony komunikat o pierwszym przechwyceniu wyjątku. Następnie wyjątek jest ponownie zgłaszany. W bloku zewnętrznym następuje drugie przechwycenie, wyświetlenie drugiego komunikatu oraz kolejne zgłoszenie wyjątku. Poniewa nie istnieje trzeci blok VT[ECVEJ, ostatecznie wyjątek jest obsługiwany przez maszynę wirtualną. Po uruchomieniu zobaczymy widok zaprezentowany na rysunku 4.15. Rysunek 4.15. Przechwytywanie i ponowne zgłaszanie wyjątków W identyczny sposób będą zachowywały się wyjątki w przypadku kaskadowego wywo- ływania metod. Z sytuacją tego typu mieliśmy do czynienia w przypadku przykładu z listingu 4.8. W klasie 'ZCORNG były wtedy zadeklarowane cztery metody: OCKP, H, I, J. Metoda OCKP wywoływała metodę H, ta z kolei metodę I, a metoda I metodę J. W ka dej
  • 27. 174 Praktyczny kurs Java z metod znajdował się blok VT[ECVEJ, jednak zawsze działał tylko ten najbli szy miejsca wystąpienia wyjątku (por. lekcja 20.). Zmodyfikujemy więc kod z listingu 4.8 tak, aby za ka dym razem wyjątek był po przechwyceniu ponownie zgłaszany. Kod realizujący to zadanie jest przedstawiony na listingu 4.18. Listing 4.18. RWDNKE ENCUU 'ZCORNG ] RWDNKE XQKF H ] VT[] I _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC H VJTQY G _ _ RWDNKE XQKF I ] VT[] J _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC I VJTQY G _ _ RWDNKE XQKF J ] KPV=? VCD PGY KPV=? VT[] VCD=? _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC J VJTQY G _ _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZ PGY 'ZCORNG VT[] GZH _ ECVEJ #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 9[LæVGM OGVQFC OCKP VJTQY G _ _ _
  • 28. Rozdział 4. ♦ Wyjątki 175 Wszystkie wywołania metod pozostały niezmienione, w ka dym bloku ECVEJ została natomiast dodana instrukcja VJTQY ponownie zgłaszająca przechwycony wyjątek. Ry- sunek 4.16 pokazuje efekty uruchomienia przedstawionego kodu. Widać wyraźnie, jak wyjątek jest propagowany po wszystkich metodach, począwszy od metody J a skoń- czywszy na metodzie OCKP. Poniewa w bloku VT[ECVEJ metody OCKP jest on ponow- nie zgłaszany, na ekranie jest tak e widoczna reakcja maszyny wirtualnej. Rysunek 4.16. Kaskadowe przechwytywanie wyjątków Tworzenie własnych wyjątków Programując w Javie, nie musimy zdawać się na wyjątki systemowe, które dostajemy wraz z JDK. Nic nie stoi na przeszkodzie, aby tworzyć własne klasy wyjątków. Wystar- czy więc, e napiszemy klasę pochodną pośrednio lub bezpośrednio z klasy 6JTQYCDNG, a będziemy mogli wykorzystywać ją do zgłaszania naszych własnych wyjątków. W prak- tyce jednak wyjątki wyprowadzamy z klasy 'ZEGRVKQP i klas od niej pochodnych. Klasa taka w najprostszej postaci będzie miała postać: RWDNKE ENCUU PCYCAMNCU[ GZVGPFU 'ZEGRVKQP ] VTG è MNCU[ _ Przykładowo mo emy utworzyć bardzo prostą klasę o nazwie )GPGTCN'ZEGRVKQP (wyjątek ogólny) w postaci: RWDNKE ENCUU )GPGTCN'ZEGRVKQP GZVGPFU 'ZEGRVKQP ] _ To w zupełności wystarczy. Nie musimy dodawać adnych nowych pól i metod. Ta klasa jest pełnoprawną klasą obsługującą wyjątki, z której mo emy korzystać w taki sam sposób, jak ze wszystkich innych klas opisujących wyjątki. Na listingu 4.19 jest widoczna przykładowa klasa OCKP, która generuje wyjątek )GPGTCN'ZEGRVKQP. Listing 4.19. RWDNKE ENCUU /CKP ] RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? VJTQYU )GPGTCN'ZEGRVKQP
  • 29. 176 Praktyczny kurs Java ] VJTQY PGY )GPGTCN'ZEGRVKQP _ _ W metodzie OCKP za pomocą instrukcji VJTQYU zaznaczamy, e metoda ta mo e zgłaszać wyjątek klasy )GPGTCN'ZEGRVKQP, sam wyjątek zgłaszamy natomiast przez zastosowanie instrukcji VJTQY, dokładnie w taki sam sposób, jak we wcześniejszych przykładach. Na rysunku 4.17 jest widoczny efekt działania takiego programu, faktycznie zgłoszony został wyjątek nowej klasy: )GPGTCN'ZEGRVKQP. Rysunek 4.17. Zgłaszanie własnych wyjątków Własne klasy wyjątków mo na wyprowadzać równie z klas pochodnych od 'ZEGRVKQP. Moglibyśmy np. rozszerzyć klasę #TKVJOGVKE'ZEGRVKQP o wyjątek zgłaszany wyłącznie wtedy, kiedy wykryjemy dzielenie przez zero. Klasę taką nazwalibyśmy KXKFG$[GTQ å'ZEGRVKQP. Miałaby ona postać widoczną na listingu 4.20. Listing 4.20. RWDNKE ENCUU KXKFG$[GTQ'ZEGRVKQP GZVGPFU #TKVJOGVKE'ZEGRVKQP ] _ Mo emy teraz zmodyfikować program z listingu 4.15 tak, aby po wykryciu dzielenia przez zero był zgłaszany wyjątek naszego nowego typu, czyli KXKFG$[GTQ'ZEGRVKQP. Klasa taka została przedstawiona na listingu 4.21. Listing 4.21. RWDNKE ENCUU 'ZCORNG ] RWDNKE FQWDNG H KPV NKEDC KPV NKEDC ] KH NKEDC VJTQY PGY KXKFG$[GTQ'ZEGRVKQP TGVWTP NKEDC NKEDC _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZCORNG PGY 'ZCORNG FQWDNG Y[PKM GZCORNGH 5[UVGOQWVRTKPVNP 9[PKM RKGTYUGIQ FKGNGPKC Y[PKM
  • 30. Rozdział 4. ♦ Wyjątki 177 Y[PKM GZCORNGH 5[UVGOQWVRTKPVNP 9[PKM FTWIKGIQ FKGNGPKC Y[PKM _ _ W stosunku do kodu z listingu 4.15 zmiany nie są du e, ograniczają się do zmiany typu zgłaszanego wyjątku w metodzie H. Zadaniem tej metody nadal jest zwrócenie wyniku dzielenia argumentu NKEDC przez argument NKEDC. W metodzie OCKP dwukrotnie wywołujemy metodę H, pierwszy raz z prawidłowymi danymi i drugi raz z danymi, które spowodują wygenerowanie wyjątku. Efekt działania przedstawionego kodu jest widoczny na rysunku 4.18. Rysunek 4.18. Zgłoszenie wyjątku DivideByZeroException Zwróćmy jednak uwagę, e pierwotnie (listing 4.15) przy zgłaszaniu wyjątku para- metrem konstruktora był komunikat (czyli wartość typu 5VTKPI). Tym razem nie mo- gliśmy jej umieścić, gdy nasza klasa KXKFG$[GTQ'ZEGRVKQP nie posiada konstruktora przyjmującego jako parametr obiektu typu 5VTKPI, a jedynie bezparametrowy kon- struktor domyślny. Aby zatem mo na było przekazywać nasze własne komunikaty, nale y dopisać do klasy KXKFG$[GTQ'ZEGRVKQP odpowiedni konstruktor. Przyjmie ona wtedy postać widoczną na listingu 4.22. Listing 4.22. RWDNKE ENCUU KXKFG$[GTQ'ZEGRVKQP GZVGPFU #TKVJOGVKE'ZEGRVKQP ] RWDNKE KXKFG$[GTQ'ZEGRVKQP 5VTKPI UVT ] UWRGT UVT _ _ Teraz instrukcja VJTQY z listingu 4.21 mogłaby przyjąć np. następującą postać: VJTQY PGY KXKFG$[GTQ'ZEGRVKQP KGNGPKG RTG GTQ NKEDC NKEDC Sekcja finally Do bloku VT[ mo emy dołączyć sekcję HKPCNN[, która będzie wykonana zawsze, nie- zale nie od tego, co będzie działo się w bloku VT[. Schematycznie taka konstrukcja będzie wyglądała następująco:
  • 31. 178 Praktyczny kurs Java VT[] KPUVTWMELG OQIæEG URQYQFQYCè Y[LæVGM _ ECVEJ ] KPUVTWMELG UGMELK ECVEJ _ HKPCNN[] KPUVTWMELG UGMELK HKPCNN[ _ Zgodnie z tym, co zostało napisane wcześniej, instrukcje sekcji HKPCNN[ są wykonywane zawsze, niezale nie od tego, czy w bloku VT[ wystąpi wyjątek, czy nie. Obrazuje to przykład z listingu 4.23, który jest oparty na kodzie z listingów 4.20 i 4.21. Listing 4.23. RWDNKE ENCUU 'ZCORNG ] RWDNKE FQWDNG H KPV NKEDC KPV NKEDC ] KH NKEDC VJTQY PGY KXKFG$[GTQ'ZEGRVKQP KGNGPKG RTG GTQ NKEDC NKEDC TGVWTP NKEDC NKEDC _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZCORNG PGY 'ZCORNG FQWDNG Y[PKM VT[] Y[PKM GZCORNGH _ ECVEJ KXKFG$[GTQ'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 2TGEJY[EGPKG Y[LæVMW _ HKPCNN[] 5[UVGOQWVRTKPVNP 5GMELC HKPCNN[ _ VT[] Y[PKM GZCORNGH _ ECVEJ KXKFG$[GTQ'ZEGRVKQP G] 5[UVGOQWVRTKPVNP 2TGEJY[EGPKG Y[LæVMW _ HKPCNN[] 5[UVGOQWVRTKPVNP 5GMELC HKPCNN[ _ _ _ Jest to znana nam klasa 'ZCORNG z metodą H wykonującą dzielenie przekazanych jej argumentów. Tym razem metoda H pozostała bez zmian w stosunku do wersji z listingu 4.21, czyli zgłasza błąd KXKFG$[GTQ'ZEGRVKQP. Zmodyfikowaliśmy natomiast metodę
  • 32. Rozdział 4. ♦ Wyjątki 179 OCKP. Oba wywołania metody zostały ujęte w bloki VT[ECVEJHKPCNN[. Pierwsze wywołanie nie powoduje powstania wyjątku, nie jest więc wykonywany pierwszy blok ECVEJ, jest natomiast wykonywany pierwszy blok HKPCNN[. Tym samym na ekranie pojawi się napis 5GMELC HKPCNN[ . Drugie wywołanie metody H powoduje wygenerowanie wyjątku, zostaną zatem wyko- nane zarówno instrukcje bloku ECVEJ, jak i instrukcje bloku HKPCNN[. Na ekranie pojawią się zatem dwa napisy: 2TGEJY[EGPKG Y[LæVMW oraz 5GMELC HKPCNN[ . Ostatecznie wyniki działania całego programu będzie taki, jak ten zaprezentowany na rysunku 4.19. Rysunek 4.19. Blok finally jest wykonywany niezale nie od tego, czy pojawi się wyjątek Sekcję HKPCNN[ mo na zastosować równie w przypadku instrukcji, które nie powodują wygenerowania wyjątku. Stosujemy wtedy instrukcję VT[HKPCNN[ w postaci: VT[] KPUVTWMELG _ HKPCNN[] KPUVTWMELG _ Działanie jest takie samo jak w przypadku bloku VT[ECVEJHKPCNN[, to znaczy kod z bloku HKPCNN[ zostanie wykonany zawsze, niezale nie od tego, jakie instrukcje znajdą się w bloku VT[. Przykładowo: nawet jeśli w bloku VT[ znajdzie się instrukcja TGVWTP lub zostanie wygenerowany wyjątek, blok HKPCNN[ i tak zostanie wykonany. Obrazuje to przykład zaprezentowany na listingu 4.24. Listing 4.24. RWDNKE ENCUU 'ZCORNG ] RWDNKE KPV H ] VT[] TGVWTP _ HKPCNN[] 5[UVGOQWVRTKPVNP 5GMELC HKPCNN[ H _ _ RWDNKE XQKF H ] VT[] KPV NKEDC _
  • 33. 180 Praktyczny kurs Java HKPCNN[] 5[UVGOQWVRTKPVNP 5GMELC HKPCNN[ H _ _ RWDNKE UVCVKE XQKF OCKP 5VTKPI CTIU=? ] 'ZCORNG GZCORNG PGY 'ZCORNG GZCORNGH GZCORNGH _ _ Ćwiczenia do samodzielnego wykonania 22.1. Napisz klasę 'ZCORNG, w której zostaną zadeklarowane metody H i OCKP. W meto- dzie H napisz dowolną instrukcję generującą wyjątek 0WNN2QKPVGT'ZEGRVKQP. W metodzie OCKP wywołaj metodę H, przechwyć wyjątek za pomocą bloku VT[ECVEJ. 22.2. Zmodyfikuj kod z listingu 4.17 tak, aby generowany, przechwytywany i ponownie zgłaszany był wyjątek #TTC[+PFGZ1WV1H$QWPFU'ZEGRVKQP. 22.3. Napisz klasę o takim układzie metod, jak w przypadku klasy 'ZCORNG z listingu 4.18. W najbardziej zagnie d onej metodzie J wygeneruj wyjątek #TKVJOGVKE'ZEGRVKQP. Przechwyć ten wyjątek w metodzie I i zgłoś wyjątek klasy nadrzędnej do #TKVJOGVKE å'ZEGRVKQP, czyli 4WPVKOG'ZEGRVKQP. Wyjątek ten przechwyć w metodzie H i zgłoś wyjątek nadrzędny do 4WPVKOG'ZEGRVKQP, czyli 'ZEGRVKQP. Ten ostatni wyjątek prze- chwyć w klasie OCKP. 22.4. Napisz klasę wyjątku o nazwie 0GICVKXG8CNWG'ZEGRVKQP oraz klasę 'ZCORNG, która będzie z niego korzystać. W klasie 'ZCORNG napisz metodę o nazwie H, przyjmującą dwa argumenty typu KPV. Metoda H powinna zwracać wartość będącą wynikiem odejmo- wania argumentu pierwszego od argumentu drugiego. W przypadku jednak, gdyby wynik ten był ujemny, powinien zostać zgłoszony wyjątek 0GICVKXG8CNWG'ZEGRVKQP. Dopisz metodę OCKP, która przetestuje działanie metody H.