正常 - try catch break java
finallyブロックは常にJavaで実行されますか? (20)
このコードを考慮すると、 something()
が何であってもfinally
ブロックが常に実行されることを絶対に確信できますか?
try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("i don't know if this will get printed out.");
}
答えは簡単です。
入力:
try{
int divideByZeroException = 5 / 0;
} catch (Exception e){
System.out.println("catch");
return; // also tried with break; in switch-case, got same output
} finally {
System.out.println("finally");
}
出力:
catch
finally
Java言語仕様の正式な言葉は次のとおりです。
14.20.2。 try-finallyとtry-catch-finallyの実行
finally
ブロックを含むtry
文は、最初にtry
ブロックを実行することによって実行されます。 次に選択肢があります:
try
ブロックの実行が正常に完了した場合、[...]- 値Vの
throw
のためにtry
ブロックの実行が突然完了した場合、[...]try
ブロックの実行が他の理由Rのために突然完了した場合、finally
ブロックが実行されます。 次に選択肢があります:
- finallyブロックが正常に完了すると、
try
ステートメントは理由Rのために突然完了します。finally
ブロックが理由Sのために突然完了した場合、try
文は理由S ( および理由Rが破棄される )のために突然完了します。
return
の仕様は、実際にこれを明示的にしています:
ReturnStatement: return Expression(opt) ;
Expression
を持たないreturn
文は、それを含むメソッドまたはコンストラクタの呼び出し側に制御を移そうとします。
Expression
を持つreturn
文は、それを含むメソッドの呼び出し側に制御を移そうとします。Expression
の値はメソッド呼び出しの値になります。
try
ブロックにreturn
文が含まれているメソッドまたはコンストラクタ内にtry
文がある場合、それらのtry
文のfinally
節が実行されるため、前述の説明では「 制御を移す 」という記述があります。順序は、コントロールがメソッドまたはコンストラクターの呼び出し側に転送される前に、最も内側から最外側に移動します。finally
節が突然完了すると、return
文によって開始された制御の転送が中断される可能性があります。
finallyブロックは、JVMのクラッシュまたはSystem.exit(0)
への呼び出しの結果、異常なプログラムの終了がない限り、常に実行されます。
さらに、finallyブロック内から返された値は、finallyブロックの実行前に返された値を上書きするため、tryを最後に使用するときはすべての終了ポイントをチェックするように注意してください。
finallyブロックは、例外ハンドルかどうかを常に実行します。tryブロックの前に例外が発生した場合、finallyブロックは実行されません。
あなたが持っているどのような場合でもファイナルは常に呼び出されるからです。 あなたは例外を持っていない、それはまだ呼び出されている、例外をキャッチ、それはまだ呼び出されています
いいえ、必ずしも例外ではありません// System.exit(0); 最終ブロックが最終的に実行されることを防止する。
class A {
public static void main(String args[]){
DataInputStream cin = new DataInputStream(System.in);
try{
int i=Integer.parseInt(cin.readLine());
}catch(ArithmeticException e){
}catch(Exception e){
System.exit(0);//Program terminates before executing finally block
}finally{
System.out.println("Won't be executed");
System.out.println("No error");
}
}
}
これについて考える論理的な方法は次のとおりです。
- finallyブロックに配置されたコードは、tryブロック内で発生したものであれば実行する必要があります
- したがって、tryブロック内のコードが値を返そうとしたり、例外をスローしようとすると、finallyブロックが実行できるようになるまで、アイテムは「シェルフ上に」配置されます
- finallyブロックのコードは(定義によって)高い優先順位を持つため、好きなものを返すかスローすることができます。 この場合、棚の上に残ったものはすべて廃棄されます。
- これに対する唯一の例外は、VMがtryブロック中に完全にシャットダウンする場合(例: 'System.exit'
これについて考える論理的な方法は次のとおりです。
finallyブロックに配置されたコードは、tryブロック内で発生したものであれば実行する必要があります。
したがって、tryブロック内のコードが値を返そうとしたり、例外をスローしようとすると、finallyブロックが実行できるようになるまで、アイテムは 'on the shelf'に置かれます。finallyブロックのコードは、(優先的に)好きなものは何でも。 この場合、棚の上に残ったものはすべて廃棄されます。
これに対する唯一の例外は、VMがtryブロック中に完全にシャットダウンする場合(例: 'System.exit'
finallyブロックから例外をスローしない
try {
someMethod(); //Throws exceptionOne
} finally {
cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever
}
cleanUp()が例外をスローすることができない限り、これは問題ありません。 上記の例でsomeMethod()が例外をスローし、finallyブロックでもcleanUp()が例外をスローすると、その2番目の例外はメソッドから出てきて元の最初の例外(正しい理由)が永久に失われます。 finallyブロックで呼び出したコードが例外をスローする可能性がある場合は、そのコードを処理するか、またはログに記録してください。 最終的にブロックから出てこないようにしてください。
実際には、System.exit()を呼び出すか、プロセスを強制終了させる致命的なエラー(Windowsでは "非ホットスポット"または "Dr Watson"と呼ばれることもあります)を実行してプログラムを終了すると、finallyブロックが実行!
try / catch / finallyブロックを入れ子にするのを止めることは何もありません(例えば、try / catchブロック内にtry / finallyブロックを入れたり、逆にするなど)。
これは実際にどの言語でも真実です...最終的にreturn文の前に実行されます。 そうでない場合、最終的なブロックはあまり意味がありません。
そうです。 JVMが終了したりクラッシュすることはありません
はい、 finally
tryまたはcatchコードブロックの実行後に呼び出されます。
finally
には呼び出されない唯一の時間は次のとおりです。
-
System.exit()
を呼び出すと、 - JVMが最初にクラッシュした場合。
- JVMが
try
ブロックまたはcatch
ブロック内の無限ループ(または他の割り込み不可能な非終了文)に達した場合、 - OSが強制的にJVMプロセスを終了した場合。 例えばUNIXでは "kill -9"となります。
- ホストシステムが停止した場合。 電源障害、ハードウェアエラー、OSパニックなどの問題が発生する可能性があります。
- finallyブロックがデーモンスレッドによって実行され、他のすべての非デーモンスレッドが最後に呼び出される前に終了する場合。
はい、そうです。 tryまたはcatchブロックで何が起こっても、System.exit()が呼ばれたり、JVMがクラッシュしたりしない限り、ブロックされます。 ブロック内にreturn文がある場合、そのreturn文の前にfinallyが実行されます。
はい、最終的にブロックは常に実行されます。 開発者のほとんどは、このブロックを使用してデータベース接続、結果セットオブジェクト、ステートメントオブジェクトを閉じ、トランザクションをロールバックするためにJavaの休止状態を使用します。
また、悪い習慣ですが、finallyブロック内にreturn文があると、それは正規ブロックからの他の戻り値よりも優先されます。 つまり、次のブロックはfalseを返します。
try { return true; } finally { return false; }
finallyブロックから例外をスローするのと同じことです。
コード例:
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
出力:
finally trumps return.
0
他のレスポンスに加えて、try..catchブロックによって例外/戻り値をオーバーライドする権利が「finally」にあることを指摘することが重要です。 たとえば、次のコードは12を返します。
public static int getMonthsInYear() {
try {
return 10;
}
finally {
return 12;
}
}
同様に、次のメソッドは例外をスローしません。
public static int getMonthsInYear() {
try {
throw new RuntimeException();
}
finally {
return 12;
}
}
次のメソッドはそれをスローしますが、
public static int getMonthsInYear() {
try {
return 12;
}
finally {
throw new RuntimeException();
}
}
具体的には、Javaの公式文書(ここをクリック)では、次のように書かれています。
tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックが実行されないことがあります。 同様に、tryまたはcatchコードを実行しているスレッドが中断または終了した場合、アプリケーション全体が継続してもfinallyブロックは実行されないことがあります。
最終的には、(System.exit(0)を呼び出すなどの)プログラムの異常終了がなければ、常に実行されます。 そうすれば、あなたのsysoutは印刷されます
次のプログラムを考えてみましょう。
public class someTest {
private static StringBuilder sb = new StringBuilder();
public static void main(String args[]) {
System.out.println(someString());
System.out.println("---AGAIN---");
System.out.println(someString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Java 1.8.162以降、上記のコードブロックは次のように出力されます。
-abc-
---AGAIN---
-abc-xyz-abc-
これは、 finally
にオブジェクトを解放することは、次のコードのような良い習慣であることを意味します:
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null;
}
}
私は少し修正して上記の例を試しました。
public static void main(final String[] args) {
System.out.println(test());
}
public static int test() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
}
}
上記のコードは次のように出力します。
ついに復帰する。
2
これは、 return i;
実行されたi
の値は2です。この後、 finally
ブロックが実行され、12がi
割り当てられ、その後System.out
が実行されます。
finally
ブロックを実行した後、 try
ブロックは、このreturn文が再度実行されないため、12を返すのではなく、2を返します。
Eclipseでこのコードをデバッグすると、 System.out
を実行した後にtry
ブロックのreturn
文が再度実行されたと感じるようになります。 しかし、そうではありません。 これは単に値2を返します。