Programowanie Obiektowe Ćwiczenie 4 1. Zakres ćwiczenia wyjątki kompozycja 2. Zagadnienia Założeniem, od którego nie należy odbiegać, jest by każdy napotkany problem (np. zatrzymanie wykonywanej metody) należy odpowiednio rozwiązać, a nie zignorować. Nie zawsze jednak wiadomo co zrobić ze specyficznym zachowaniem. W takiej sytuacji należy przekazać problem dalej czyli zgłosić wyjątek. Wyjątek jest specjalnym obiektem, który posiada dodatkowy atrybut pozwalający go rzucić, czyli wywołać w ściśle zdefiniowanej sytuacji. Operacja ta jest wykonywana poprzez użycie słowa kluczowego throw. Gdy zostaje rzucony wyjątek następuje: utworzenie obiektu wyjątku poprzez słowo kluczowe new, przerwanie działania programu/wątku i przejście do miejsca obsługi wyjątku, czyli procedury, której zadaniem jest zgłoszenie informacji o błędzie i zastosowanie rozwiązania pozwalającego, jeśli to możliwe, dalsze funkcjonowanie aplikacji. public class Example { public double divide(int divident,int divisior){ if (divisior == 0){ throw new ArithmeticException("Dividing by zero"); else{ return divident/divisior; Obiekty, które mogą rzucać poprzez słowo throw należą do klas, które dziedziczą po klasie Throwable, Rys. 1. Jak łatwo zauważyć, dziedziczą po niej dwie klasy: Error i Exception. Do klasy Error należą wszystkie błędy, które nie wynikają z kodu oprogramowania bądź błędu użytkowania oprogramowania lecz gdy, np. zabraknie pamięci lub dojdzie do przepełnienia stosu, Rys. 2. Błędów/obiektów tej klasy nie trzeba obsługiwać (unchecked exceptions), są one rzucane przez maszynę wirtualną. Błędy wynikające z użytkowania oprogramowania lub błędów w kodzie zawierają się w klasie Exception. W klasie tej można wyróżnić wyjątki typu RunTimeExceptions, których nie trzeba deklarować ani obsługiwać (unchecked exceptions), co zaprezentowano na rysunku 3. Inne typy wyjątków klasy Exceptions oznaczone barwą zieloną należy obsłużyć (checked exceptions). 1
Object (java.lang.object) Throwable (java.lang.throwable) Error (java.lang.error) Exception (java.lang.exception) Rysunek 1: Hierarchia klas w Java Error (java.lang.error) java.lang.assertionerror java.lang.linkageerror java.lang.threaddeath java.lang.virtualmachineerror Rysunek 2: Hierarchia Klasy Error Exception (java.lang.exception) java.lang.clonenotsupported Exception java.lang.interrupte dexception java.lang.reflectiveoperati onexception java.lang.runtimeexcep tion Rysunek 3: Hierarchia Klasy Exception 2
Do obsługi wyjątków służy blok try - catch - finally. Pierwsza sekcja try{ jest obligatoryjna. W niej umieszcza się część kodu, która ma być zabezpieczona przed szczególnym zachowaniem oprogramowania, tj. wystąpieniem wyjątku. Do czasu wystąpienia wyjątku, kod jest wykonywany normalnie, a jeśli wyjątek w ogóle nie wystąpi to sekcja catch{ jest pomijana. W następstwie po try{ musi wystąpić dowolna z kolejnych sekcji: catch{ lub finally{, mogą też wystąpić obie lub można wielokrotnie wykorzystać blok catch{. Przykłady każdego z wymienionych bloków znajdują się w ramkach poniżej. Wymagane jest by w przypadku użycia obu bloków, catch{ zawsze występowało przed finally{. W sekcji catch{ umieszcza się kod, który zostanie wykonany w wypadku wystąpienia zdefiniowanego wyjątku. Jeśli wykorzystuje się wiele sekcji catch{ to istotna jest kolejność ich umieszczania w kodzie, ponieważ zostanie wykonana pierwsza napotkana i pasująca typem zgłaszanego wyjątku instrukcja, a kolejne nie będą sprawdzane. Ważne jest także precyzyjne zdefiniowanie łapanego wyjątku, bowiem umieszczenie zbyt ogólnego przypadku przed bardziej szczegółowym, spowoduje jego zbyt wczesną obsługę. Możliwe jest również łapanie różnych wyjątków poprzez wymienienie ich w jednej sekcji catch z wykorzystaniem znaku w ten sposób: catch(ioexception IllegalArgumentException e) { Sekcję finally{ charakteryzuje wykonanie niezależnie od tego czy wyjątek został rzucony czy też nie. Wykona się zawsze. Obsługa wyjątków blok: try catch Example e = new Example(); int x = 0; double result; try{ result = e.divide(5,x); catch(arithmeticexception exception){ result = e.divide(5,x-1); System.out.println(result); 3
Obsługa wyjątków blok: try catch finally Example e = new Example(); int x = 0; double result; try{ result = e.divide(5,x); catch(arithmeticexception exception){ result = e.divide(5,x-1); finally { System.out.println("That was finally section"); System.out.println(result); Obsługa wyjątków blok: try finally Example e = new Example(); int x = 0; double result; try{ result = e.divide(5,x); finally { System.out.println("That was finally section"); System.out.println(result); Tworzenie własnych wyjątków Dostępna lista wyjątków, z których można skorzystać jest bogata. Zdarzyć się jednak może, że żaden z nich niezbyt dokładnie odpowiada projektowanej rzeczywistości. W takim wypadku możliwe jest stworzenie własnych wyjątków. Aby stworzyć nową klasę wyjątków konieczne jest dziedziczenie po klasie już utworzonej, najlepiej takiej, która najbliższa jest nowotworzonej. Jeśli nie jest to możliwe, można dziedziczyć po klasie Exception. Zawsze należy zapoznać się z dokumentacją dotyczącą danej klasy i jeśli jest to konieczne wywołać odpowiednie konstruktory. Reszta jest analogiczna do tworzenia zwykłej klasy. 4
Wykorzystanie istniejących klas w postaci ich obiektów jako składowe nowych klas określa się mianem kompozycji. Kompozycja zaraz obok dziedziczenia stanowi ważny mechanizm ponownego wykorzystanie wcześniej napisanego kodu, a ich stosowanie jest powszechne. public class Index { private String course; private int id; private double grade; public void setid(int id) { this.id = id; public int getid() { return id; public void setcourse(string course) { this.course = course; public String getcourse() { return course; public void setgrade(double grade) { this.grade = grade; public double getgrade() { return grade; 5
public class Student { private Index index; private String name; public Student(String name, int id){ this.index = new Index(); setname(name); index.setid(id); index.setcourse("math"); index.setgrade(4.0); public void setname(string name) { this.name = name; public String getname() { return name; public String getcourse() { return index.getcourse(); public double getgrade() { return index.getgrade(); Student zak = new Student("Kowalski", 1111111); System.out.println(zak.getCourse()); 3. Zadania do wykonania 1) Zapoznaj się z dokumentacją na stronie Oracle dotyczącą podstawowych wyjątków i na jej podstawie wykorzystaj w kolejnych zadaniach. https://docs.oracle.com/javase/7/docs/api/java/lang/package-tree.html 2) Korzystając z metody Integer.parseInt() napisz kod, który będzie zamieniał wprowadzone przez użytkownika znaki na liczbę typu int. Zapewnij odpowiednią obsługę wyjątków. 3) Napisz program listujący na konsolę zawartość wskazanego przez użytkownika n- tego elementu wcześniej utworzonej tablicy. 4) Zmodyfikuj program 1-3 napisany podczas laboratorium nr 2, tak aby wykorzystywał on zarówno kompozycję jak i dziedziczenie. 6