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

Transkrypt

Wykład 8: Obsługa Wyjątków
Wykład 8:
Obsługa Wyjątków
Wyjątki
Wyjątek to sytuacja nienormalna, która pojawia się w
trakcie wykonania programu.
W językach bez obsługi wyjątków, błędy są wykrywane i
obsługiwane ręcznie, zwykle przez kody błędów.
Java dostarcza specjalnych konstrukcji językowych do
sygnalizacji, wykrywania i obsługi błędów.
Wyjątki w Javie
Wyjątek to obiekt, który opisuje sytuację wyjątkową
(błędną) powstałą w kodzie programu:
●
●
●
Kiedy powstaje błąd, wyjątek opisujący go jest
"wyrzucany" w metodzie która ten błąd spowodowała.
Metoda może "wyłapać" i "obsłużyć" wyjątek
samodzielnie, lub przekazać go dalej.
Błąd jest na koniec wyłapany i obsługiwany.
Konstrukcje Obsługi Wyjątków
try – otacza część programu, którą chcemy
monitorować na wypadek sygnalizacji błędów
●
catch – w parze z try, wyłapuje określone wyjątki i
obsługuje je w pewien sposób
●
throw – sygnalizuje powstanie określonego wyjątku
●
throws – określenie jakie wyjątki może dana metoda
sygnalizować
●
finally – kod, który musi być koniecznie wywołany
przed opuszczeniem danej metody
●
Blok Obsługi Wyjątków
Blok try/catch/finally do obsługi dwóch rodzajów
wyjątków (TypWyjatku1 i TypWyjatku2):
try {
//monitorowana część kodu
} catch(TypWyjatku1 e) {
//obsluga wyjatku dla typu 1
} catch(TypWyjatku2 e) {
//obsluga wyjatku dla typu 2
} finally {
//kod do wykonanie przed zakonczeniem
}
Hierarchia Wyjątków
●
Throwable – obejmuje wszystkie wyjątki
●
Exception – wyjątki do wyłapania przez
programy użytkowe
●
RuntimeException – definiowane
automatycznie dla programów:
●
dzielenie przez zero
●
indeksowanie tablic
●
itp.
●
TypWyjatku – wyjątki użytkownika
●
Error – nie do wyłapania przez programy
użytkowe, błędy środowiska wykonawczego
Domyślna Obsługa Wyjątków
class Wyjatek0 {
public static void main(String args[]) {
int d = 0;
int a = 42 / d;
}
}
Gdy system wykrywa dzielenie przez zero, tworzy nowy
obiekt wyjątku, i wyrzuca go.
Z braku własnej procedury obsługi, wyjątek jest
przechwycony przez procedurę domyślną, która
wyświetla komunikat, stos wywołań i powoduje
zakończenie.
Domyślna Obsługa Wyjątków
Stos wywołań: ciąg wywołań metod które prowadziły do
wystąpienia błędu.
class Wyjatek1 {
static void metoda() {
int d = 0;
int a = 10 / d;
}
public static void main(String args[]) {
Wyjatek1.metoda();
}
}
Własna Obsługa Wyjątków
Korzyści własnej obsługi błędów: umożliwia poprawianie
błędów, zapobiega zakończeniu działania programu.
class Wyjatek2 {
public static void main(String args[]) {
int d, a;
Należy umieścić kod do monitorowania w bloku try:
try {
d = 0;
a = 42 / d;
System.out.println("Nieosiągalne");
}
Własna Obsługa Wyjątków
Należy określić które wyjątki chcemy wyłapać:
catch (ArithmeticException e) {
Oraz jak te wyjątki obsłużyć:
}
System.out.println("Dzielenie przez 0");
Kod po obsłudze wyjątku:
}
}
System.out.println("Po wyjatku");
Try i Catch
Bloki try i catch stanowią parę.
Gdy wyrzucany jest wyjątek w bloku try:
try {
d = 0;
a = 42 / d;
System.out.println("Nieosiągalne");
kontrola przechodzi natychmiast do bloku catch:
} catch (ArithmeticException e) { ... }
catch nie może wyłapać wyjątków z innych bloków try,
z wyłączeniem zagnieżdżonych bloków try.
Maskowanie Błędów
Wyjątek jest obsługiwany, potem program kontynuuje
tak jakby nic się nie wydarzyło.
Generowanie liczb losowych:
import java.util.Random;
class ObslugaBledow {
public static void main(String args[]) {
int a = 0, b = 0, c = 0;
Random r = new Random();
Maskowanie Błędów
Obsługa błędu gdy jedna z pary liczb jest zerem:
}
}
for (int i=0; i<32000; i++) {
try {
b = r.nextInt();
c = r.nextInt();
a = 12345 / (b / c);
} catch (ArithmeticException e) {
System.out.println("Dzielenie przez 0");
a = 0;
}
System.out.println("i: " + i + "a: " + a);
}
Wyświetlanie Opisu Wyjątku
Klasa Throwable przesłania metodę toString() tak
by wyświetlała opis wyjątku.
try { ... }
catch (ArithmeticException e) {
System.out.println("Wyjatek: " + e);
a = 0;
}
Obsługa Kilku Wyjątków Na Raz
Jeden blok try i kilka catch dla różnych wyjątków.
class WieleBledow {
public static void main(String args[]) {
try {
int a = args.length;
System.out.println("a= " + a);
Ryzyko dzielenia przez zero:
int b = 42 / a;
Indeks poza zakresem tablicy:
int c[] = { 1 }; c[42] = 99;
Obsługa Kilku Wyjątków Na Raz
Wyłapanie i obsługa błędu dzielenia przez zero:
} catch(ArithmeticException e) {
System.out.println("Dzielenie przez 0");
Wyłapanie i obsługa błędu indeksowania poza tablicą:
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Index poza tablica");
}
Kod po obsłudze błędów:
}
System.out.println("Po obsludze bledow");
}
Kolejność Obsługi Wyjątków
W sekwencji catch, wyjątki pod-klasy muszą wystąpić
przed wyjątkami nad-klasy. Pojawi się błąd kompilacji:
class WyjatekPodKlasa {
public static void main(String args[]) {
try {
int a = 0;
int b = 42 / a;
} catch(Exception e) {
System.out.println("Wyjatek generyczny");
} catch(ArithmeticException e) {
System.out.println("Nieosiagalny");
}
}
}
Zagnieżdżony Blok try
Jeden blok try wewnątrz innego try.
class ZagniezdzonyTry {
public static void main(String args[]) {
Zewnętrzny blok try:
try {
int a = args.length;
Ryzyko dzielenia przez zero:
int b = 42 / a;
System.out.println("a= " + a);
Zagnieżdżony Blok try
Wewnętrzny blok try:
try {
Ryzyko dzielenia przez zero:
if (a == 1) a = a /(a-a);
Wykroczenie poza zakres tablicy:
if (a == 2) {
int c[] = {1};
c[42] = 99;
}
Zagnieżdżony Blok try
Obsługa wyjątku wykroczenia poza zakres tablicy
powstałego w bloku wewnętrznym try:
} catch(ArrayIndexOutOfBoundsException e){
System.out.println("Index za tablica");
}
Obsługa wyjątku błędu dzielenia przez zero powstałego
w bloku zewnętrznym try:
}
}
} catch (ArithmeticException e) {
System.out.println("Dzielenie przez 0);
}
Zagnieżdżony Blok try
wyjątek powstaje w bloku wewnętrznym try i jest
obsłużony przez catch w tym samym bloku
●
wyjątek powstaje w bloku wewnętrznym try i jest
obsłużony przez catch w bloku zewnętrznym
●
wyjątek powstaje w bloku zewnętrznym try i jest
obsłużony przez catch w bloku zewnętrznym
●
brakuje instrukcji catch w obu blokach - wyjątek
obsługiwany jest przez środowisko wykonawcze
●
Metody i Występowanie Bloków try
class MetodaZagniezdzonyTry {
Metoda z wewnętrznym blokiem try:
static void zagniezdzonyTry(int a) {
try {
if (a == 1) a = a /(a-a);
if (a == 2) {
int c[] = {1};
c[42] = 99;
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index poza tablica);
}
}
Metody i Występowanie Bloków try
Metoda z zewnętrznym blokiem try:
}
public static void main(String args[]) {
try {
int a = args.length;
int b = 42 / a;
System.out.println("a= " + a);
zagniezdzonyTry(a);
} catch (ArithmeticException e) {
System.out.println("Dzielenie przez 0);
}
}
Wyrzucanie Wyjątków
Program użytkownika może sam wyrzucać wyjątki:
throw object;
Obiekt musi być klasy Throwable, albo jej pod-klasy.
Uzyskanie obiektu klasy Throwable:
●
użycie operatora new
●
użycie parametru w instrukcji catch
Obsługa throw
Przerwanie wykonania na instrukcji throw:
czy najbliższy otaczający blok try posiada
instrukcję catch dla obsługi danego wyjątku?
●
w przeciwnym razie, czy kolejny otaczający blok try
posiada tą instrukcję?
●
w przeciwnym razie, wykonaj domyślną obsługę
wyjątku: przerwanie wykonania, drukowanie stosu
●
Demonstracja throw
class ThrowDemo {
static void metoda() {
try {
Tworzy nowy wyjątek i go wyrzuca:
throw new NullPointerException("demo");
Wyjątek jest wyłapany natychmiast:
} catch(NullPointerException e) {
System.out.println("Zlapany w metodzie");
Demonstracja throw
Obsługa polega na przesłaniu wyjątku dalej:
}
}
throw e;
Wyjątek jest złapany ponownie przez metodę main:
}
public static void main(String args[]) {
try {
metoda();
} catch(NullPointerException e) {
System.out.println("Zlapany ponownie");
}
}
Tworzenie Standardowych Wyjątków
Tworzenie obiektu standardowej klasy wyjątku:
throw new NullPointerException("demo");
Wszystkie standardowe wyjątki mają dwa konstruktory:
bezparametrowy
●
z parametrem String opisującym wyjątek; dostępny
przez getMessage() w Throwable
●
Deklaracja throws
Jeśli metoda może spowodować wyjątek którego sama
nie jest w stanie obsłużyć, to musi ten fakt opisać.
typ nazwa(parametry) throws wyjatki { ... }
Niezbędne jest wymienienie wszystkich wyjątków,
oprócz typów Error i RuntimeException.
Brak Deklaracji throws
Metoda wyrzuca wyjątek którego ani nie wyłapuje, ani
nie deklaruje. Ten program nie kompiluje się.
class ThrowsDemo1 {
static void metoda() {
System.out.println("Wewnatrz metody");
throw new IllegalAccessException("demo");
}
public static void main(String args[]) {
metoda();
}
}
Dodana Deklaracja throws
Jedna metoda deklaruje, druga wyłapuje wyjątek:
class ThrowsDemo2 {
static void metoda()
throws IllegalAccessException {
System.out.println("Wewnatrz metody");
throw new IllegalAccessException("demo");
}
public static void main(String args[]) {
try {
metoda();
} catch (IllegalAccessException e) {
System.out.println("Zlapany " + e);
}
}
}
Deklaracja finally
Kod który będzie wykonany po bloku try/catch, bez
względu na powstanie wyjątków.
Użyteczny gdy należy zwolnić zasoby systemowe.
Każdy try musi posiadać co najmniej jedną instrukcję
catch lub finally.
Demonstracja finally
class FinallyDemo {
static void procA() {
try {
System.out.println("wewnatrz procA");
throw new RuntimeException("demo");
} finally {
System.out.println("procA: finally");
}
}
static void procB() {
try {
System.out.println("wewnatrz procB");
return;
} finally {
System.out.println("procB: finally");
}
}
Demonstracja finally
}
static void procC() {
try {
System.out.println("wewnatrz procC");
} finally {
System.out.println("procC: finally");
}
}
public static void main(String args[]) {
try {
procA();
} catch(Exception e) {
System.out.println("Wyjatek zlapany");
}
procB();
procC();
}
Standardowe Wyjątki Niesprawdzane
RuntimeException są dostępne automatycznie.
Nie muszą być deklarowane w sekcji throws.
Kompilator nie sprawdza czy metoda deklaruje czy
obsługuje te wyjątki.
Inaczej wyjątki niesprawdzane.
Standardowe Wyjątki Niesprawdzane
ArithmeticException błędy arytmetyczne, np.
dzielenie przez zero
●
ArrayIndexOutOfBoundsException indeks
tablicy poza zakresem
●
ArrayStoreException przypisanie tablicy
nieodpowiedniego typu elementu
●
ClassCastException niepoprawne rzutowanie
●
IllegalArgumentException niepoprawny
argument metody
●
IllegalMonitorStateException niepoprawna
operacja monitora
●
Standardowe Wyjątki Niesprawdzane
IllegalStateException środowisko lub aplikacja
jest w niepoprawnym stanie
●
IllegalThreadStateException wymagana
operacja niekompatybilna z bieżącym stanem wątka
●
IndexOutOfBoundException jakis rodzaj indeksu
jest poza zakresem
●
NegativeArraySizeException tablica tworzona z
ujemnym rozmiarem
●
NullPointerException niepoprawne użycie
wskaźnika null
●
Standardowe Wyjątki Niesprawdzane
NumberFormatException niepoprawna konwersja
stringu na format liczbowy
●
SecurityException próba naruszenia
bezpieczeństwa
●
StringIndexOutOfBoundsException indeks poza
zakresem stringu
●
UnsupportedOperationException napotkano
niepoprawną operację
●
Standardowe Wyjątki Sprawdzane
Metody która mogą generować te wyjątki a nie potrafią
ich samodzielnie obsłużyć, muszą je deklarować:
ClassNotFoundException nie znaleziono klasy
●
CloneNotSupportedException próba klonowania
obiektu który nie implementuje interfejsu
Cloneable.
●
IllegalAccessException dostęp do klasy
zabroniony
●
InstantiationException próba tworzenia obiektu
klasy abstrakcyjnej lub interfejsu
●
Standardowe Wyjątki Sprawdzane
InterruptedException jeden wątek przerwany
przed drugi
●
NoSuchFieldException pole nie istnieje
●
NoSuchMethodException metoda nie istnieje
●
Tworzenie Własnych Klas Wyjątków
Utwórz pod-klasę Exception.
Pod-klasa nie musi nic deklarować, musi tylko istnieć.
Exception nie deklaruje własnych metod, ale
dziedziczy po Throwable.
Demonstracja Własnych Klas Wyjątków
Własna klasa wyjątków:
class MojWyjatek extends Exception {
private int szczegoly;
MojWyjatek(int a) {
szczegoly = a;
}
Przesłonięcie metody z klasy Throwable:
}
public String toString() {
return "MojWyjatek[" + szczegoly + "]";
}
Demonstracja Własnych Klas Wyjątków
class MojeWyjatki {
Metoda deklaruje wyjątek tej klasy:
static void oblicz(int a) throws MojWyjatek {
System.out.println("oblicz(" + a + ")");
Wyrzucenie wyjątku:
}
if (a > 10) throw new MojWyjatek(a);
System.out.println("Normalne wyjscie");
Demonstracja Własnych Klas Wyjątków
public static void main(String args[]) {
try {
oblicz(1);
oblicz(20);
Przechwycenie wyjątku:
}
}
} catch (MojWyjatek e) {
System.out.println("Zlapany " + e);
}

Podobne dokumenty