Luty 18, 2019

Java pytanie rekrutacyjne: Wykonywanie bloku finally

Czym blok finally jest wykonywany w przypadku złapania wyjątku?

W przypadku, gdy mamy blok try catch możemy dodać kolejny blok finally, który powinnien wykonywać się zawsze. Jednak czy na pewno jest to prawda? Co w przypadku, gdy złapiemy wyjątek lub zwrócimy wartość z metody już w bloku try?

Przetestujmy to na prostych przykładach:

package pl.rekrutacja.pytanie;

public class Main {

    public static void main(String[] args) {
        try {
            divideWithCatch(1, 0);
        } catch (ArithmeticException e) {
            e.printStackTrace();
        }
        finally {
            System.out.println("Blok finally w main.");
        }
        divideWithoutCatch(2, 1);
        divideWithoutCatch(2,0);
    }

    private static double divideWithCatch(int a, int b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            e.printStackTrace();
            throw e;
        } finally {
            System.out.println("Blok finally w metodzie divideWithCatch");
        }
    }

    private static double divideWithoutCatch(int a, int b) {
        try {
            return a / b;
        } finally {
            System.out.println("Blok finally w metodzie divideWithoutCatch");
        }
    }
}

Mamy dwie metody – jednak z blokiem catch, drugi zaś tylko z blokami try oraz finally. Uruchamiając taki kod otrzymamy taki rezultat:

java.lang.ArithmeticException: / by zero
  at pl.rekrutacja.pytanie.Main.divideWithCatch(Main.java:20)
  at pl.rekrutacja.pytanie.Main.main(Main.java:7)
java.lang.ArithmeticException: / by zero
  at pl.rekrutacja.pytanie.Main.divideWithCatch(Main.java:20)
  at pl.rekrutacja.pytanie.Main.main(Main.java:7)
Exception in thread "main" java.lang.ArithmeticException: / by zero
  at pl.rekrutacja.pytanie.Main.divideWithoutCatch(Main.java:31)
  at pl.rekrutacja.pytanie.Main.main(Main.java:15)
Blok finally w metodzie divideWithCatch
Blok finally w main.
Blok finally w metodzie divideWithoutCatch
Blok finally w metodzie divideWithoutCatch

Na pierwszy rzut oka już widać, mając cztery bloki finally otrzymujemy dokładnie z nich cztery komunikaty. Wniosek jest oczywisty – blok finally wykonuje się zawsze. Bez względu na to czy użyliśmy return w bloku try, czy wcześniej rzuciliśmy wyjątek w bloku catch.

Po co blok finally

Zazwyczaj nie używa się bloku finally, ma jednak on swoje przeznaczenie. Często używa się go do „posprzątania” po sobie – mówiąc o sprzątaniu mam na myśli np. zamykanie strumienii, plików, połączeń itd.