15. JAVA – wyjątki


W Java występują błędy kompilacji oraz wyjątki, które mogą się pojawić w trakcie trwania programu. W takim wypadku skrypt kończy swoje działanie, a istnieją sytuacje, w których nie jest to konieczne np. praca na nieistniejącym pliku.
Możliwe błędy najlepiej przechwycić w trakcie wykonywania skryptu, żeby nie powodować sytuacji, w której program zakończy swoje działanie błędem.

Mówimy, że wyjątki przechwytują błędy.

Wyjątki wyświetlają stosowną informację dla użytkownika w przypadku błędu i umożliwiają kontynuację pracy skryptu.

Wyjątki są obiektami klasy Exception, które posiadają własny komunikat i kod błędu. Mogą one zostać wyłapane (try), rzucone (throw) i przechwycone (catch).

 

try…, catch…

Przykład. Obsłużymy wyjątek polegający na odwołaniu się do nieistniejącego elementu w tablicy:

public class TryCatch {
public static void main(String[] args) {
int[] numbers = {0,1,2,3,4,5,6};
try{
int nr = numbers[7]; //nie ma takiego elementu w tablicy
} catch(ArrayIndexOutOfBoundsException e) { //możemy w nawiasie podać ogólnie typ klasy "Exception e" lub jak w tym przypadku podać konkretny rodzaj wyjątku
System.out.println("Wystąpił błąd");
//jeżeli potrzebujemy dodatkowych informacji na temat błędu warto skorzystać z metody printStackTrace
e.printStackTrace();
}
System.out.println("Po obsłużeniu błędu program kontynuuje swoją pracę");
}
}

 

try…, catch…, finally…

Jeżeli chcemy, aby instrukcja zawsze wywołała się bez względu na powstanie wyjątku lub nie, używamy bloku finally. Możemy tą instrukcję wykonać np. gdy chcemy zamknąć dany zasób po wykonaniu operacji na plikach.

Przykład. (modyfikujemy powyższy)

public class TryCatchFinally {
public static void main(String[] args) {
int[] numbers = {0,1,2,3,4,5,6};
try{
int nr = numbers[7]; //nie ma takiego elementu w tablicy
} catch(Exception e) {
System.out.println("Wystąpił błąd: nie ma takiego elementu w tablicy");
} finally {
System.out.println("Instrukcja wywołana zawsze");
}
System.out.println("Po obsłużeniu błędu program kontynuuje swoją pracę");
}
}

Przykład. Obsługa więcej niż 1 wyjątku.

public class TryCatchFinallyMoreThanOne {
public static void main(String[] args) {
int[] numbers = {0,1,2,3,4,5,6};
try{
int divide = 2/numbers[0]; //błąd dzielenia przez 0 - ten wyjątek wystąpi jako pierwszy więc ten komunikat się pojawi: Wystąpił błąd: nie wolno dzielić przez 0
int nr = numbers[7]; //nie ma takiego elementu w tablicy
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Wystąpił błąd: nie ma takiego indeksu w tablicy");
} catch (ArithmeticException e){
System.out.println("Wystąpił błąd: nie wolno dzielić przez 0");
} finally {
System.out.println("Instrukcja wywołana zawsze");
}
System.out.println("Po obsłużeniu błędu program kontynuuje swoją pracę");
}
}

Wiele wyjątków możemy zapisać razem, po znaku „|” np.

catch(ArrayIndexOutOfBoundsException | ArithmeticException e)... 

 

throw…

W zależności od potrzeb, wyjątki możemy też zgłaszać.

public class Throw {
public static void main(String[] args) {
try {
int l1 = 2;
int l2 = 0;

//będziemy wykonywali dzielenie liczb, a jak wiemy nie można dzielić przez 0
//jeżeli dzielnik będzie 0 to tworzymy nowy obiekt klasy wyjątku
if (l2 == 0) throw new ArithmeticException();
int divide = l1 / l2;
} catch (ArithmeticException ae) {
System.out.println("Wystąpił błąd arytmetyczny");
ae.printStackTrace();//wyświetlamy szczegóły
}
System.out.println("Program kontynuuje pracę");
}
}

 

Możemy zdefiniować własną klasę wyjątku, dziedziczy ona po klasie Exception:

import java.util.Random;

class MyException extends Exception{
public MyException(){
System.out.println("Error");
}
}

public class ThrowClass {
static void mozeZglosicWyjatek() throws MyException {
int x = new Random().nextInt(5);
if (x == 0) throw new MyException();
System.out.println("Wylosowano " + x);
}

public static void main(String[] args) {
try {
mozeZglosicWyjatek();
} catch (MyException me) {
System.out.println("Wylosowano 0, zgłaszam wyjątek");
}
System.out.println("Program kontynuuje pracę");
}
}

 

Wyjątki możemy zgłaszać poprzez metodę:

import java.util.Random;

public class ThrowMethod {
void mozeZglosicWyjatek() throws Exception {
int x = new Random().nextInt(5);
if (x == 0) throw new Exception();
System.out.println("Wylosowano " + x);
}

public static void main(String[] args) {

ThrowMethod z = new ThrowMethod();
try {
z.mozeZglosicWyjatek();
} catch (Exception e) {
System.out.println("Wylosowano 0, zgłaszam wyjątek");
}
System.out.println("Program kontynuuje pracę");
}
}

 

Przykład: Kalkulator.

import java.util.Scanner;

public class Calculator {
public static void main(String[] args) {
Scanner user_data = new Scanner(System.in);

System.out.println("Podaj pierwszą liczbę: ");
String l1 = user_data.nextLine();

System.out.println("Podaj drugą liczbę: ");
String l2 = user_data.nextLine();

System.out.println("Podaj znak: ");
String sign = user_data.nextLine();

try {
int liczba1 = Integer.parseInt(l1);
int liczba2 = Integer.parseInt(l2);

switch (sign) {
case "+":
int sum = liczba1 + liczba2;
System.out.println(l1+"+"+l2 + "=" +String.valueOf(sum));
break;
case "-":
int minus = liczba1 - liczba2;
System.out.println(l1+"-"+l2 + "=" +String.valueOf(minus));
break;
case "*":
int multi = liczba1 * liczba2;
System.out.println(l1+"*"+l2 + "=" +String.valueOf(multi));
break;
case "/":
float divide = (float)liczba1 / (float)liczba2;
System.out.println(l1+"/"+l2 + "=" +String.valueOf(divide));
break;

default:
System.out.println("Nierozpoznany wybór");
break;
}
/* //to samo tylko z ifami
if(sign.equals("+")){
int sum = liczba1 + liczba2;
System.out.println(l1+"+"+l2 + "=" +String.valueOf(sum));
} else if(sign.equals("-")){
int minus = liczba1 - liczba2;
System.out.println(l1+"-"+l2 + "=" +String.valueOf(minus));
} else if(sign.equals("*")){
int multi = liczba1 * liczba2;
System.out.println(l1+"*"+l2 + "=" +String.valueOf(multi));
} else if(sign.equals("/")){
int divide = liczba1 / liczba2;
System.out.println(l1+"/"+l2 + "=" +String.valueOf(divide));
}
*/
} catch (NumberFormatException e) {
System.out.println("Pierwsza i druga wartość musi być liczbą");
} catch (ArithmeticException e){
System.out.println("Nie wolno dzilić przez 0");
} finally {
System.out.println("Wyjątki zostały obsłużone, program działa dalej.");
}

}
}