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.