try-catch-finally句内の実行順序とreturnについて

try-catch-finally句とは

例外が発生しそうな処理をtryブロック、例外時の処理をcatchブロック、例外の有無に問わず必ず実行する処理をfinallyブロックで囲い込むことです。

try-catch-finally句内の実行順序とreturn

例外が発生しない 且つ try-catch-finally句の中で、returnをする場合

サンプルA

 public class Test {
     public static void main(String[] args) {
         String ret = getReturn();
         System.out.println(ret);
     }
 
     public static String getReturn(){
         String str = "try's return";
         try {
             System.out.println("try start");
             str.toString();     // 例外が発生しない
             return str;
         }catch (Exception e){ 
             System.out.println("catch start");
             str = "catch's return";
             return str;
         }finally {
             System.out.println("finally start");
             str = "finally's return";
             return str;
         }
     }
 }

実行結果

 try start
 finally start
 finally's return

try句の処理を実行したあとにfinally句の処理が実行されています。

finally句でreturnは実行されますが、try句のreturnは実行されません。

例外が発生した 且つ try-catch-finally句の中で、returnをする場合

サンプルB

 public class Test {
     public static void main(String[] args) {
         String ret = getReturn();
         System.out.println(ret);
     }
 
     public static String getReturn(){
         String str = null;
         try {
             System.out.println("try start");
             str.toString();     // 例外が発生
             return str;
         }catch (Exception e){ 
             System.out.println("catch start");
             str = "catch's return";
             return str;
         }finally {
             System.out.println("finally start");
             str = "finally's return";
             return str;
         }
     }
 }

実行結果

 try start
 catch start
 finally start
 finally's return

catch句の処理を実行したあとにfinally句の処理が実行されています。

finally句でreturnは実行されますが、catch句のreturnは実行されません。

例外が発生した 且つ try-catch-finally句の中で、returnをする場合

サンプルC

public class Test {
     public static void main(String[] args) {
         String ret = getReturn();
         System.out.println(ret);
     }
 
     public static String getReturn(){
         String str = null;
         try {
             System.out.println("try start");
             str.toString();     // 例外が発生
             return str;
         }catch (Exception e){ 
             System.out.println("catch start");
             str = "catch's return";
             return str;
         }finally {
             System.out.println("finally start");
             str = "finally's return";
         }
         System.out.println("end");
         return str;
     }
 }

実行結果

 try start
 catch start
 finally start
 catch's return

finally句で変数strの値を変更していますがreturnがないので、戻り値は上書きされることはなく、catch句の設定値のままです。

戻り値がインスタンスの場合

サンプルD

 public class Stu {
     String name;
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
 }

 public class Test {
     public static void main(String[] args) {
         Stu ret = getReturn();
         System.out.println(ret.getName());
     }
 
     public static Stu getReturn(){
         Stu stu = new Stu();
         try {
             System.out.println("try start");
             stu.setName("try's return");
             return stu;
         }catch (Exception e){ 
             System.out.println("catch start");
             stu.setName("catch's return");
             return stu;
         }finally {
             System.out.println("finally start");
             stu.setName("finally's return");
         }
         System.out.println("end");
         return stu;
     }
 }

実行結果

 try start
 finally start
 finally's return

finally句でnameの値が変更されていましたstuがreturnされています。

まとめ

  • finally句の処理が例外の有無に問わず、returnする前に必ず実行されます。
  • finally句でreturnがある場合、優先で実行されます。
  • finally句でreturnがない場合、戻り値の値がfinally句を実行する前にお決まりです。
    つまり、finally句で変数の値を変更しても、戻り値は変わりません。
    但し、インスタンス変数の変更なら、戻り値は変わります。
  • finallyブロック内で値の変更処理やreturn処理を記載しますと、他人が理解しにくいため、お勧めしません。

Smallitのサービス