JAva try catch finally実行順序まとめ

10927 ワード

目次
戻り値の実行順序
try内return,finally特殊動作しない
try内return,finallyもreturn
try内return,finally前returnの内容を修正する
try内returnの前に異常が発生し、finallyとcatchが変数を変更します.
try内に異常が発生し、catch内return、finallyで各種動作を行う 
returnまとめ
異常を投げ出す
catchで異常を投げ出し、finallyは特殊な動作をしない
catchから異常が投げ出され、finally return
catchで異常を投げ出し、finallyでも異常を投げ出す
catchから異常が投げ出され、finallyはcatchの異常をキャプチャしようとした.
catch内放出異常まとめ
戻り値の実行順序
try内return,finally特殊動作しない
public class FinallyTest1 {

    public static void main(String[] args) {
        
        System.out.println(test1());
    }

    public static int test1() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80; 
        }
        catch (Exception e) {

            System.out.println("catch block");
        }
        finally {
            
            System.out.println("finally block");
            
            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }
        }
        
        return b;
    }
    
}

実行結果:
try block
finally block
b>25, b = 100
100

説明tryのreturn文はすでに実行されており、finally文を実行しますが、直接戻るのではなく、finally文が実行されてから結果を返します.
この例がまだこの状況を説明するのに十分ではないと思ったら、次の例を加えて証明の結論を強化します.
public class FinallyTest1 {

    public static void main(String[] args) {
        
        System.out.println(test11());
    }
    
    public static String test11() {
        try {
            System.out.println("try block");

           return test12();
      } finally {
           System.out.println("finally block");
       }
  }

  public static String test12() {
       System.out.println("return statement");

       return "after return";
   }
    
}

実行結果:
try block
return statement
finally block
after return

説明tryのreturn文は先に実行したがすぐに返さず、after returnという文字列を保存し、finally実行が終了してからこの文字列を返し、mainプログラムに印刷させる
ここではfinallyにもreturn文があれば、そのまま戻ってしまい、tryのreturnは戻ってこないのではないかと思うかもしれません.下を見てください.
 
try内return,finallyもreturn
public class FinallyTest2 {

    public static void main(String[] args) {

        System.out.println(test2());
    }

    public static int test2() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            return 200;
        }

        // return b;
    }

}

実行結果:
try block
finally block
b>25, b = 100
200

これはfinallyのreturnが直接戻ってきたことを示しています.tryに戻ってくる文があるかどうかにかかわらず、ここには小さな詳細があります.finallyにreturnを加えると、finallyの外のreturn bは到達不可能な文になります.つまり、永遠に実行できません.注釈が必要です.そうしないと、コンパイラが間違っています.
ここで、finallyにreturn文がないのにbの値を変更した場合、tryのreturnは修正後の値を返しますか、それとも元の値を返しますか.下を見てください.
try内return,finally前returnの内容を修正する
public class FinallyTest3 {

    public static void main(String[] args) {

        System.out.println(test3());
    }

    public static int test3() {
        int b = 20;

        try {
            System.out.println("try block");

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b = 150;
        }

        return 2000;
    }

}

実行結果:
try block
finally block
b>25, b = 100
100

tryのreturnに相当します  100では、100という値が格納され、bという変数が格納されていないため、finallyの変更は無効であり、finallyが終了すると、直接100に戻り、return 2000は実行されません.
import java.util.*;

public class FinallyTest6
{
    public static void main(String[] args) {
        System.out.println(getMap().get("KEY").toString());
    }
     
    public static Map getMap() {
        Map map = new HashMap();
        map.put("KEY", "INIT");
         
        try {
            map.put("KEY", "TRY");
            return map;
        }
        catch (Exception e) {
            map.put("KEY", "CATCH");
        }
        finally {
            map.put("KEY", "FINALLY");
            map = null;
        }
         
        return map;
    }
}

実行結果:
FINALLY

tryのreturnに相当します  mapの場合、mapという変数のアドレスが格納されており、mapという変数が格納されているわけではないので、finallyのmapという変数に対応するオブジェクトを修正した内容に対して、mapはnullのためmapのアドレスを修正したが、無効であり、アドレスが格納されているため
なぜテスト例1のfinallyのb=150であるか.テスト例2ではfinallyのmap.put("KEY","FINALLY");機能してmapは = null;役に立たなかったの?
これがJavaが値を伝えるかアドレスするかという問題で、簡単に言えば、Javaの中で値を伝えるだけでアドレスがないのも、map=nullという言葉が役に立たない理由です.
これはまた、戻り文がfinallyの外側のreturn bではなくtryのreturn文であることを示している.この文
信じなければ、return bを試してみてください.return 294に変更すると、元の結果には少しも影響しません.
ここで皆さんはまた、tryのreturn文が毎回返されるのではないかと考えているかもしれません.ではfinally外のreturn bは少しも役に立たないのではないでしょうか.下を見てください.
try内returnの前に異常が発生し、finallyとcatchが変数を変更します.
public class FinallyTest4 {

    public static void main(String[] args) {

        System.out.println(test4());
    }

    public static int test4() {
        int b = 20;

        try {
            System.out.println("try block");

            b = b / 0;

            return b += 80;
        } catch (Exception e) {

            b += 15;
            System.out.println("catch block");
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b += 50;
        }

        return b;
    }

}

実行結果:
try block
catch block
finally block
b>25, b = 35
85

ここでreturnの前に0を除く異常が発生したため、try中のreturnは実行されず、次に異常をキャプチャしたcatch文と最終的なfinally文が実行され、このとき両者のbに対する修正は最終的な戻り値に影響し、このときreturn b;役に立ちました.
もちろん、ここでreturn bをreturn 300に変更したりして、最後に戻ったのは300であることは間違いありません.
ここで疑問に思うかもしれませんが、catchにreturn文があれば?もちろん異常の場合のみ実行可能ですが、finallyの前に戻るのでしょうか?下を見てください.
try内に異常が発生し、catch内return、finallyで各種動作を行う 
public class FinallyTest5 {

    public static void main(String[] args) {

        System.out.println(test5());
    }

    public static int test5() {
        int b = 20;

        try {
            System.out.println("try block");
            
            b = b /0;

            return b += 80;
        } catch (Exception e) {

            System.out.println("catch block");
            return b += 15;
        } finally {

            System.out.println("finally block");

            if (b > 25) {
                System.out.println("b>25, b = " + b);
            }

            b += 50;
        }

        //return b;
    }

}

実行結果は次のとおりです.
try block
catch block
finally block
b>25, b = 35
35

異常が発生した場合、catchのreturn文は先に実行され、戻り値が確定してからfinallyブロックを実行し、catchを実行してから戻り、finallyのbの変更は戻り値に影響を及ぼさないことを説明した.原因は前と同じで、つまりtryのreturn文の実行と完全に同じである.
b=b+50になってからreturn bに行くと、tryとcatchで返されるbの値が変更されます.
returnまとめ
最後に、finallyブロックの文はtryまたはcatchのreturn文が実行された後、戻る前に実行されます.
またfinallyの修正文はtryやcatchでreturnが決定した戻り値(数値は影響せず、参照は影響しない)に影響しない可能性があり、finallyにreturn文がある場合はtryやcatchのreturn文を上書きし、直接戻ります.
異常を投げ出す
catchで異常を投げ出し、finallyは特殊な動作をしない
	public static void main(String[] args) {

		System.out.println(test());
	}

	public static String test() {
		try {
			System.out.println("try block");
			int a = 1 / 0;
			return "try result";
		} catch (Exception e) {
			System.out.println("catch block");
			int b = 1 / 0;
			return "catch result";

		} finally {
			System.out.println("finally block");
			//return "finally result";
		}
	}

catchが異常を放出した後、finallyは実行を継続し、放出された異常bを保持し、その後放出を継続する
Exception in thread "main"java.lang.ArithmeticException:/by zero     at test.t05new.Test9.test(Test9.java:27)     at test.t05new.Test9.main(Test9.java:17) try block catch block finally block
catchから異常が投げ出され、finally return
	public static String test() {
		try {
			System.out.println("try block");
			int a = 1 / 0;
			return "try result";
		} catch (Exception e) {
			System.out.println("catch block");
			int b = 1 / 0;
			return "catch result";

		} finally {
			System.out.println("finally block");
			return "finally result";
		}
	}

try block catch block finally block finally result
returnはcatchから放出された異常をクリアしました
catchで異常を投げ出し、finallyでも異常を投げ出す
	public static void main(String[] args) {

		System.out.println(test());
	}

	public static String test() {
		try {
			System.out.println("try block");
			int a = 1 / 0;
			return "try result";
		} catch (Exception e) {
			System.out.println("catch block");
			int b = 1 / 0;
			return "catch result";

		} finally {
			System.out.println("finally block");
			int c = 1 / 0;
			return "finally result";
		}
	}

try block catch block finally block Exception in thread "main"java.lang.ArithmeticException:/by zero     at test.t05new.Test9.test(Test9.java:32)     at test.t05new.Test9.main(Test9.java:17)
finallyが投げた異常はcatchが投げた異常に代わった
 
catchから異常が投げ出され、finallyはcatchの異常をキャプチャしようとした.
	public static void main(String[] args) {

		System.out.println(test());
	}

	public static String test() {
		try {
			System.out.println("try block");
			int a = 1 / 0;
			return "try result";
		} catch (Exception e) {
			System.out.println("catch block");
			int b = 1 / 0;
			return "catch result";

		} finally {			
			System.out.println("finally block");
			try {
				System.out.println("finally block2");
			} catch (Exception e2) {
				System.out.println("finally block3");
				return "finally result";
			}
			//int c = 1 / 0;
			//return "finally result";
		}
	}

try block catch block finally block finally block2 Exception in thread "main"java.lang.ArithmeticException:/by zero     at test.t05new.Test9.test(Test9.java:27)     at test.t05new.Test9.main(Test9.java:17)
異常bがキャプチャされていないことがわかり、異常bはプログラムによって保持され、finallyに渡されていない.
catch内放出異常まとめ
catch内に異常が投げ出され、catch内のプロセスが中断され、プログラム内にこの異常が保存され、finallyが正常に実行され、内部returnまたは異常が投げ出された場合、プログラムが終了し、returnまたはfinally内の異常がcatchの異常を上書きします.