Java: return w try-catch-finally

Jedno z typowych zadań pojawiających się od czasu do czasu na rozmowach (lub egzaminach:)) polega na stwierdzeniu, który blok zostanie wykonany jako ostatni i jaka wartość zostanie zwrócona.

W poniższym przykładzie kolejność wypisywanych tekstów jest zgodna z numerami:

try {
  System.out.println("Try");//1
  throw new Exception();
} catch (Exception ex) {
  System.out.println("Catch");//2
} finally {
  System.out.println("Finally");//3
}
System.out.println("Function");//4

Zatem wynik to po prostu:
Try
Catch
Finally
Function

Jak natomiast zachowa się funkcja zawierająca return w każdym z bloków (try/catch/finally/ciele funkcji)?

public String test() {
  try {
    throw new Exception();
    //return "From try"; //unreachable code
  } catch (Exception ex) {
    return "From catch";//Lost!
  } finally {
    // Inspection warning: "finally block can not complete normally"
    // Inspection warning: return inside 'finally' block. While occasionally intended, such return statements may mask exceptions thrown, and tremendously complicate debugging.
    return "From finally";//Will be return
  }
  //return "From function"; //unreachable code
}

Mam nadzieję, że komentarze są jasne:

  • Return w bloku try nie wykona się – wcześniej zostanie rzucony wyjątek.
  • Return w bloku catch zostanie nadpisany przez wartość zwróconą w finally
  • Return w bloku finally zwróci wartość, środowisko IntelliJ wyświetla natomiast ostrzeżenia iż jest to niepoprawne użycie tej konstrukcji.
  • Return poza blokiem try/catch/finally pozostający w ciele funkcji zostanie… pominięty, gdyż wcześniej wykona się wyjście z funkcji w bloku finally.

Tak samo zachowa się konstrukcja, gdzie pominięto blok catch. W tym przypadku wyjątek zostanie podrzucony w górę, do funkcji nadrzędnej, ponieważ nie zostanie złapany (brak catch). Zwrócona zostanie wartość z bloku finally, a ewentualne późniejsze operacje wykonywane w ciele funkcji, za blokiem finally – pominięte.

Przydatny wpis? Postaw mi kawę :)