728 x 90

Kurs programowania Java. Część 6: Wyjątki

Kurs programowania Java. Część 6: Wyjątki

1. Zadanie 1

Dzisiejsze zadanie to zaimplementować klasę LapanieWyjatkow zawierającą metodę obliczOdwrotnosc(-), która jako parametr pobiera tablicę liczb. Każdy element tablicy modyfikujemy obliczając jego odwrotność, czyli
dzieląc 1 przez niego samego.

Łatwo się domyślić, że w przypadku pewnych danych nasze obliczenie nie powiedzie się. Jakich danych? Na przykład wartości 0.

Rozwiązaniem jest dodanie w metodzie obsługi wyjątków: Exception, NullPointerException i ArithmeticException.

1.1. Rozwiązanie

Rozpoczniemy od utworzenia pliku {LapanieWyjatkow.java}, w którym
umieścimy rozwiązanie zadania.

public class LapanieWyjatkow {

Dalej, w utworzonym pliku rozpoczynamy definicję klasy.

static void obliczOdwrotnosc(double[] tablica) {

Tworzymy metodę statyczną {obliczOdwrotnosc}, która jako argument przyjmuje tablice liczb zmiennoprzecinkowych.
W celu przechwycenia określonych w treści zadania wyjątków otwieramy klauzule {try…catch}.

for (int i = 0; i < tablica.length; ++i) {
 tablica[i] = 1. / tablica[i];
 }

 } catch (NullPointerException ex) {
 System.err.println("NullPointerException");
 } catch (ArithmeticException ex) {
 System.err.println("ArithmeticException");
 } catch (Exception ex) {
 System.err.println("Exception");
 }
 }

Dokonujemy obliczeń odwrotności liczb iterując wszystkie
elementy tablicy w pętli.

Następnie przechwytujemy określone wyjątki. W prezentowanym przykładzie
pierwszym jest NullPointerException, który może wystąpić, gdy
do metody zostanie przekazana nie zainicjowana tablica liczb.
Drugim przechwytywanym wyjątkiem jest ArithmeticException,
którego przykładem wystąpienia jest dzielenie przez zero. Oba te wyjątki są niezależne od siebie,
dlatego mogą wystąpić również w odwrotnej kolejności.
Wyjątkiem, który musi zostać przechwycony jako ostatni jest
Exception. Jego zadaniem jest przechwycenie pozostałych
nieprzewidzianych wyjątków w kodzie sekcji try.
Ponieważ pozostałe dwa wcześniejsze wątki dziedziczą po
klasie Exception, sam kompilator zgłosi błąd jeśli przechwycenie
tego wyjątku znajdzie się przed poprzednimi.

public static void main(String[] args) {
 double tab[] = {1., 17., 3., 0.};
 obliczOdwrotnosc(tab);
 obliczOdwrotnosc(null);
 }
 }

Na koniec, w metodzie głównej main, defniujemy przykładową tablicę
liczb i wywołujemy metodę obliczOdwrotnosc najpierw na tej tablicy,
a następnie przekazując stałą null jako argument.
Celem takiego wywołania jest obserwacja przechwycenia opisanych wyżej
dwóch wyjątków szczegółowych.

2. Zadanie 2: Przekazywanie wyjątków

Zmodyfikuj klasę utworzoną w zadaniu pierwszym tak, aby przekazywała do
kontekstu wyżej wyjątek NullPointerException.
Należy tak poprawić program, aby nadal obsługiwał wszystkie wyjątki
wypisując na ekran nazwę wyjątku oraz stan stosu wywołań metod programu.

1.1. Rozwiązanie

W celu rozwiązania zadania wykorzystamy klasę utworzoną w poprzednim
zadaniu.

public class LapanieWyjatkow {

Podobnie jak poprzednio, na początku rozpoczynamy definicją klasy.

static void obliczOdwrotnosc(double[] tablica) throws NullPointerException {

Następnie przy nagłówku metody {obliczOdwrotnosc}
dopisujemy klauzulę {throws} za którą umieszczamy
klasy wyjątków rozdzielone przecinkiem, które będą
wyrzucane do kontekstu wyżej. W przypadku tego zadania
jest to tylko wyjątek {NullPointerException}.

try {
 for (int i = 0; i < tablica.length; ++i) {
 tablica[i] = 1. / tablica[i];
 }
 } catch (ArithmeticException ex) {
 System.err.println("ArithmeticException");
 ex.printStackTrace(System.err);
 } catch (Exception ex) {
 System.err.println("Exception");
 ex.printStackTrace(System.err);
 }
 }

Dalej, modyfikujemy treść metody pozostawiając tylko obsługę wyjątków:
{ArithmeticException} i {Exception}. W sekcji {catch}
po wypisaniu nazwy wyjątku na standardowe wyjście błędu dopisujemy
instrukcję wypisującą dodatkowo stos wywołań tych metod na standardowe wyjście błędu.

 

public static void main(String[] args) {
 double tab[] = { 1., 17., 3., 0. };
 try {
 obliczOdwrotnosc(tab);
 obliczOdwrotnosc(null);
 }
 catch (NullPointerException ex) {
 System.err.println("NullPointerException");
 ex.printStackTrace(System.err);
 }
 }
 }

Główną metodę programu także w takim wypadku musimy zmodyfikować
w stosunku do rozwiązania z poprzedniego zadania. Tym razem, aby
poprawnie obsłużyć wyjątek {NullPointerException}, musimy
wywołanie metody {obliczOdwrotnosc} umieścić w sekcji
{try…catch}. Podobnie jak przy przechwytywaniu wyjątków
wewnątrz metody, w przypadku wygenerowania tego wyjątku wypisujemy
jego nazwę oraz stos wywołań metod.

Tak jak we wcześniejszym zadaniu, umieszczamy tutaj dwa wywołania metody
{obliczOdwrotnosc}, aby zaprezentować zachowanie programu
podczas wystąpienia dwóch różnych wyjątków.

 

3. Zadanie 3: Tworzenie własnych wyjątków

Utworzyć nową klasę wyjątku o nazwie {MojWyjatek}. Następnie napisać
w osobnej klasie {TestMojegoWyjatku} metodę {losuj()}, która
generuje z prawdopodobieństwem 0.25 ten wyjątek do kontekstu wyżej.
W metodzie {main} głównej klasy programu należy przechwycić ten
wyjątek oraz niezależnie od jego wystąpienia zapewnić wykonanie części kodu
wypisującego na ekran wylosowany w metodzie {losuj()} ułamek
(wykorzystać sekcję {finally}).

1.1. Rozwiązanie

Zadanie rozpoczniemy od utworzenia klasy {MojWyjatek}.

 

public class MojWyjatek extends Exception {

public MojWyjatek() {
 super("Moj Wyjatek!");
 }

}

W celu utworzenia nowego typu wyjątku należy rozszerzyć
klasę {Exception}, w której dodatkowo nadpisujemy domyślny
konstruktor podając jako dodatkową informację dla wyjątku napis “Moj Wyjatek!”.

Następnie, przechodzimy do implementacji klasy {TestMojegoWyjatku}.

public class TestMojegoWyjatku {

double los;

Definicję zaczynamy od utworzenia pola liczby rzeczywistej o dostępie pakietowym,
w którym będziemy trzymać ostatnio wylosowany ułamek.

void losuj() throws MojWyjatek {
 while (true) {
 los = Math.random();
 if (los < 0.25) {
 throw new MojWyjatek();
 }
 System.out.print(".");
 }
 }

Dalej, implementujemy metodę {losuj()}, przy której nagłówku określamy
po słowie kluczowym {throws} utworzoną wcześniej klasę wyjątku.
Wewnątrz metody wykonujemy natomiast nieskończoną pętlę, w której losujemy
liczbę z przedziału $[0, 1)$ i w zależności od wyniku generujemy wyjątek
lub wypisujemy symbol kropki (informujący o działaniu programu).

W statycznej metodzie głównej programu tworzymy obiekt utworzonej klasy.

public static void main(String[] args) {
 TestMojegoWyjatku test = new TestMojegoWyjatku();
 

try {
 test.losuj();
 System.out.println("\nKoniec");
 } catch (MojWyjatek ex) {
 System.err.println("Wyjatek: " + ex.getMessage());
 } finally {
 System.out.printf("\nWylosowano: \%.2f\n", test.los);
 }
 }
 }

A na koniec wywołujemy metodę {losuj()} utworzonego obiektu.
Jej wywołanie umieszczamy w klauzuli
{try…catch}, po której przechwytujemy wyjątek wypisując jego
dodatkowe informacje. Określamy również klauzulę {finally},
która mimo wywołanego wyjątku zostanie także wykonana w przeciwieństwie
do instrukcji wypisującej słowo “Koniec”.

Poniżej przedstawiony został wynik przykładowego uruchomienia programu.

Wyjatek: Moj Wyjatek!
 ........
 Wylosowano: 0,16

 

Leave a Comment

Your email address will not be published. Required fields are marked with *

Cancel reply

Inne artykuły