このコードを考慮して、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");
}
はい、finally
はtry
またはcatch
コードブロックの実行後に呼び出されます。
finally
が呼び出されないのは次の場合だけです。
System.exit()
を起動した場合try
ブロックまたはcatch
ブロック内で無限ループ(またはその他の中断不可能な非終了ステートメント)に到達した場合kill -9 <pid>
finally
ブロックがデーモンスレッドによって実行され、他のすべての非デーモンスレッドが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
また、悪い習慣ではありますが、finallyブロック内にreturn文があると、通常のブロックからの他のreturnよりも優先されます。つまり、次のブロックはfalseを返します。
try { return true; } finally { return false; }
Finallyブロックから例外をスローするのと同じことです。
これがJava言語仕様からの公式の言葉です。
14.20.2。 try-finallyとtry-catch-finallyの実行
try
ブロックを含むfinally
ステートメントは、最初にtry
ブロックを実行することによって実行されます。次に選択肢があります。
try
ブロックの実行が正常に完了した場合、[...]- 値Vの
try
が原因でthrow
ブロックの実行が突然完了した場合try
ブロックの実行が他の何らかの理由で突然完了した場合、R、finally
ブロックが実行されます。その後、選択肢があります。
- Finallyブロックが正常に完了した場合、
try
ステートメントは理由Rにより突然完了します。finally
ブロックがreason Sのために突然完了した場合、try
ステートメントはreason Sのために突然完了します( およびreason Rは破棄されます )。
return
の仕様では、実際にこれを明示的に示しています。
ReturnStatement: return Expression(opt) ;
return
を持たないExpression
ステートメント 試行 それを含むメソッドまたはコンストラクターの呼び出し側に制御を移します。
return
を持つExpression
ステートメント 試みる それを含むメソッドの呼び出し側に制御権を移す。Expression
の値がメソッド呼び出しの値になります。上記の説明では、メソッドまたはコンストラクタ内に
try
ブロックにtry
ステートメントが含まれているreturn
ステートメントがある場合、単なる "transfer control"ではなく、 "試み controlの転送を使用これらのfinally
ステートメントのtry
文節は、制御がメソッドまたはコンストラクターの呼び出し側に渡される前に、最も内側から外側の順に実行されます。finally
文節が突然完了すると、return
ステートメントによって開始された制御の転送が中断される可能性があります。
他の応答に加えて、 'finally'はtry..catchブロックによって例外/戻り値を上書きする権利を持つことを指摘することが重要です。たとえば、次のコードは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();
}
}
上記の例を少し修正してみました。
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
outが実行されます。
finally
ブロックを実行した後、try
ブロックは12を返すのではなく2を返します。これは、このreturn文が再度実行されないためです。
このコードをEclipseでデバッグするのであれば、System.out
of finally
ブロックを実行した後にreturn
ブロックのtry
ステートメントが再度実行されるように感じるでしょう。しかし、そうではありません。単に値2を返します。
これが Kevinの答え の詳細です。たとえ後に返されるとしても、返される式はfinally
の前に評価されることを知っておくことは重要です。
public static void main(String[] args) {
System.out.println(Test.test());
}
public static int printX() {
System.out.println("X");
return 0;
}
public static int test() {
try {
return printX();
}
finally {
System.out.println("finally trumps return... sort of");
}
}
出力:
X
finally trumps return... sort of
0
それが、finallyブロックの全体的な考え方です。もちろん、他の方法で戻るためにスキップされる可能性があるクリーンアップを確実に実行できます。
最後に呼び出されます何が起こっても tryブロックで(unlessSystem.exit(int)
またはJavaその他の理由で仮想マシンが起動します)。
これについて考えるための論理的な方法は、次のとおりです。
(System.exit(0)を呼び出すように)プログラムの異常終了がない限り、finallyは常に実行されます。だから、あなたのSYSOUTが表示されます
また、やっと戻ってきた場合は、例外がすべて捨てられます。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
JVMのクラッシュまたはSystem.exit(0)
の呼び出しによってプログラムが異常終了しない限り、finallyブロックは常に実行されます。
それに加えて、finallyブロック内から返される値は、finallyブロックの実行前に返される値をオーバーライドするため、try finallyを使うときはすべての出口点をチェックするように注意してください。
いいえ、必ずしも1つの例外ケースが// System.exit(0)です。 finallyブロックの前にfinallyが実行されるのを防ぎます。
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");
}
}
}
それがリターンの後にコードに現れるという理由だけで、最後に常に実行されていることが全体的なポイントです。 Javaランタイムは、try
ブロックを終了するときにこのコードを実行する責任があります。
たとえば、次のようになっているとします。
int foo() {
try {
return 42;
}
finally {
System.out.println("done");
}
}
ランタイムは次のようなものを生成します。
int foo() {
int ret = 42;
System.out.println("done");
return 42;
}
キャッチされていない例外がスローされた場合、finally
ブロックが実行され、例外は伝播し続けます。
これは、iの値を12として割り当てたのに、iの値を関数に返さなかったためです。正しいコードは次のとおりです。
public static int test() {
int i = 0;
try {
return i;
} finally {
i = 12;
System.out.println("finally trumps return.");
return i;
}
}
System.exit()
を呼び出さない限り(またはスレッドがクラッシュするまで)、finallyブロックが常に呼び出されるためです。
答えは簡単です _ yes _ 。
入力:
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
はい、それは呼ばれるでしょう。それがfinallyキーワードを持つことの全体的なポイントです。 try/catchブロックから飛び出してfinallyブロックを飛ばすことができれば、System.out.printlnをtry/catchの外側に置くのと同じことになります。
はい、finallyブロックは常に実行されます。開発者のほとんどは、データベース接続、ResultSetオブジェクト、Statementオブジェクトとトランザクションをロールバックするために休止状態また、Javaに使用を閉じ、このブロックを使用します。
簡潔に言えば、公式のJavaドキュメンテーション(Click here )には、 - と書かれています -
Tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックは実行されない可能性があります。同様に、tryまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続していてもfinallyブロックは実行されないことがあります。
はいそうでしょう。 JVMが終了またはクラッシュしない場合のみ
はい、できます。他の方法でSystem.exit()が呼び出されるかJVMがクラッシュしない限り、tryまたはcatchブロック内で何が発生しても関係ありません。ブロック内にreturnステートメントがある場合は、そのreturnステートメントの前に最後に実行されます。
次のプログラムを考えてください。
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());
System.out.println("---PRINT THE RESULT---");
System.out.println(sb.toString());
}
private static String someString() {
try {
sb.append("-abc-");
return sb.toString();
} finally {
sb.append("xyz");
}
}
}
Java 1.8.162以降、上記のコードブロックは次のように出力されます。
-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz
これは、オブジェクトを解放するためにfinally
を使用することは、次のコードのように良い習慣であることを意味します。
private static String someString() {
StringBuilder sb = new StringBuilder();
try {
sb.append("abc");
return sb.toString();
} finally {
sb = null; // Just an example, but you can close streams or DB connections this way.
}
}
私はこれを試した、それはシングルスレッドです。
class Test {
public static void main(String args[]) throws Exception {
Object obj = new Object();
try {
synchronized (obj) {
obj.wait();
System.out.println("after wait()");
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
メインスレッドは永遠に待ち状態になるので、最後に呼ばれることはありません。
コンソール出力は文字列を表示しません:after wait()
またはfinally
@Stephen Cに同意して、上記の例は3番目のケース言及の1つです ここ :
次のコードで、このような無限ループの可能性をさらにいくつか追加します。
// import Java.util.concurrent.Semaphore;
class Test {
public static void main(String[] args) {
try {
// Thread.sleep(Long.MAX_VALUE);
// Thread.currentThread().join();
// new Semaphore(0).acquire();
// while (true){}
System.out.println("after sleep join semaphore exit infinite while loop");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
ケース2:JVMが最初にクラッシュした場合
import Sun.misc.Unsafe;
import Java.lang.reflect.Field;
class Test {
public static void main(String args[]) {
try {
unsafeMethod();
// Runtime.getRuntime().halt(123);
System.out.println("After Jvm Crash!");
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
}
}
Ref: どうやってJVMをクラッシュさせますか?
ケース6:finallyブロックがデーモンスレッドによって実行され、デーモン以外のすべてのスレッドがfinallyが呼び出される前に終了する場合。
class Test {
public static void main(String args[]) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
printThreads("Daemon Thread printing");
// just to ensure this thread will live longer than main thread
Thread.sleep(10000);
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
};
Thread daemonThread = new Thread(runnable);
daemonThread.setDaemon(Boolean.TRUE);
daemonThread.setName("My Daemon Thread");
daemonThread.start();
printThreads("main Thread Printing");
}
private static synchronized void printThreads(String str) {
System.out.println(str);
int threadCount = 0;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
System.out.println("Thread :" + t + ":" + "state:" + t.getState());
++threadCount;
}
}
System.out.println("Thread count started by Main thread:" + threadCount);
System.out.println("-------------------------------------------------");
}
}
出力:これは、 "デーモンスレッド"の "最後のブロック"が実行されなかったことを意味する "finally"を表示しません。
main Thread Printing Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED Thread :Thread[main,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:3 ------------------------------------------------- Daemon Thread printing Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE Thread count started by Main thread:2 ------------------------------------------------- Process finished with exit code 0
はい、 制御文なし はfinally
の実行を妨げる可能性があるためです。
これは参考例で、すべてのコードブロックが実行されます。
| x | Current result | Code
|---|----------------|------ - - -
| | |
| | | public static int finallyTest() {
| 3 | | int x = 3;
| | | try {
| | | try {
| 4 | | x++;
| 4 | return 4 | return x;
| | | } finally {
| 3 | | x--;
| 3 | throw | throw new RuntimeException("Ahh!");
| | | }
| | | } catch (RuntimeException e) {
| 4 | return 4 | return ++x;
| | | } finally {
| 3 | | x--;
| | | }
| | | }
| | |
|---|----------------|------ - - -
| | Result: 4 |
以下の変形では、return x;
はスキップされます。結果はまだ4
です。
public static int finallyTest() {
int x = 3;
try {
try {
x++;
if (true) throw new RuntimeException("Ahh!");
return x; // skipped
} finally {
x--;
}
} catch (RuntimeException e) {
return ++x;
} finally {
x--;
}
}
参照は、もちろん、それらのステータスを追跡します。この例では、value = 4
を含む参照を返します。
static class IntRef { public int value; }
public static IntRef finallyTest() {
IntRef x = new IntRef();
x.value = 3;
try {
return x;
} finally {
x.value++; // will be tracked even after return
}
}
finally
が実行され、それは確かです。
以下の場合、finally
は実行されません。
ケース1:
System.exit()
を実行しているとき。
ケース2:
あなたのJVM/Threadがクラッシュした時。
ケース3:
手動で実行が途中で停止したとき。
try
- catch
- finally
は、例外処理を使用するためのキーワードです。
通常の説明文として
try {
//code statements
//exception thrown here
//lines not reached if exception thrown
} catch (Exception e) {
//lines reached only when exception is thrown
} finally {
// always executed when the try block is exited
//independent of an exception thrown or not
}
Finallyブロックが実行を妨げています...
System.exit(0);
を呼び出したとき例外を処理しない場合は、プログラムを終了する前に、JVMはfinallyブロックを実行します。以下の理由により、プログラムの通常の実行が失敗してプログラムの終了を意味する場合にのみ実行されません.
プロセスを中止させる致命的なエラーを引き起こすことによって。
メモリ破損によるプログラムの終了.
System.exit()を呼び出すことによって
プログラムが無限ループに陥った場合.
それはどの言語でも事実です...そのreturnがメソッド本体のどこにあっても、最終的には常にreturn文の前に実行されます。そうでない場合、finallyブロックはあまり意味がありません。
@ vibhashの答え に他の答えがないので、以下のような可変オブジェクトの場合に何が起こるかを説明します。
public static void main(String[] args) {
System.out.println(test().toString());
}
public static StringBuffer test() {
StringBuffer s = new StringBuffer();
try {
s.append("sb");
return s;
} finally {
s.append("updated ");
}
}
出力します
sbupdated
はい、書かれています ここ
Tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックは実行されない可能性があります。同様に、tryまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続していてもfinallyブロックは実行されないことがあります。
Tryブロック内のreturnを最後に置き換える際のreturnについての点に加えて、例外についても同じことが言えます。例外をスローするfinallyブロックは、tryブロック内からスローされたreturnまたはexceptionを置き換えます。
Java言語仕様は、try-catch-finallyブロックおよびtry-catchブロックが 14.20.2 でどのように機能するかを記述しています。
いかなる場所でも、finallyブロックが常に実行されることは指定されていません。しかし、try-catch-finallyブロックとtry-finallyブロックが完了するすべての場合において、完了前に最終的に実行しなければならないことを指定します。
try {
CODE inside the try block
}
finally {
FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).
JLSは、 _ fin _ が _ code _ の後に実行されることを保証しません。 _ code _ および _ next _ が実行されると、 _ fin _ が常に _ code _ の後に実行されることがJLSによって保証されます。そして _ next _ の前。
JLSがfinallyブロックが常にtryブロックの後に実行されることを保証しないのはなぜですか?不可能だからです。 tryブロックが完了した直後、finallyブロックが実行される前に、JVMが中止される(kill、crash、power off)可能性は低いですが可能性があります。これを避けるためにJLSができることは何もありません。
したがって、それらのtryブロックが完了した後に常に実行されている、最終的なブロックに依存する適切な動作のためのソフトウェアにはバグがあります。
Tryブロック内の戻り値は、この問題とは無関係です。 try-catch-finallyの後に実行がコードに到達した場合は、tryブロック内でreturnの有無にかかわらず、finallyブロックが以前に実行されたことが保証されます。
最後のブロックは、System.exit()が最初に呼び出された場合、またはJVMがクラッシュした場合の2つの固有のシナリオでは、復帰後に呼び出されません。
できるだけ簡単な方法であなたの質問に答えようとしましょう。
規則1 :finallyブロックは常に実行されます(ただし例外はありますが、しばらくの間はこれに固執しましょう)。
規則2 :制御がtryブロックまたはcatchブロックを離れたときにfinallyブロック内のステートメントが実行されます。制御の転送は、通常の実行、中断の実行、続行、goto、またはreturnステートメント、または例外の伝播.
Return文の場合(キャプションが付いているので)、コントロールは呼び出し元のメソッドを終了する必要があります。そして、対応するtry-finally構造体のfinallyブロックを呼び出します。 return文はfinallyブロックの後に実行されます。
Finallyブロックにreturn文がある場合、それは呼び出しスタックをクリアするので、tryブロックで保留中のものを確実に上書きします。
あなたはここでより良い説明を参照することができます: http://msdn.Microsoft.com/en-us/ ....概念はすべての高級言語でほとんど同じです。
次のコードと同じです。
static int f() {
while (true) {
try {
return 1;
} finally {
break;
}
}
return 2;
}
fは2を返します。
なぜならファイナルはあなたが持っているどんな場合でも常に呼ばれるからです。あなたは例外を持っていない、それはまだ呼ばれている、例外をキャッチ、それはまだ呼ばれている
はい、常に呼び出されますが、System.exit()を使用したときに呼び出されないことがあります。
try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
Tryブロックの前に例外が発生した場合、最後にblockは常に例外処理を実行するかどうかにかかわらず実行し、最後にblockは実行されません。
例外がスローされた場合は、最後に実行されます。例外がスローされない場合は、最後に実行されます。例外が発生した場合は、最後に実行されます。例外が捕捉されない場合は、最後に実行されます。
実行されないのは、JVMが終了したときだけです。
通常の実行の過程でこれを考慮してください(つまり、例外がスローされることはありません)。
このコードを試してみて、あなたはfinallyブロックの コードがreturn文の後に実行されることを理解するでしょう 。
public class TestTryCatchFinally {
static int x = 0;
public static void main(String[] args){
System.out.println(f1() );
System.out.println(f2() );
}
public static int f1(){
try{
x = 1;
return x;
}finally{
x = 2;
}
}
public static int f2(){
return x;
}
}
私はさまざまなフォーラムで提供されているすべての回答と非常に混乱していたので、最後にコーディングして表示することにしました。出力は次のとおりです。
try and catchブロックにreturnがあっても、ついに実行されます。
try {
System.out.println("try");
return;
//int i =5/0;
//System.exit(0 ) ;
} catch (Exception e) {
System.out.println("catch");
return;
//int i =5/0;
//System.exit(0 ) ;
} finally {
System.out.println("Print me FINALLY");
}
出力
やってみる
最後に印刷してください
System.exit(0)
に置き換えられ、その前に何らかの理由で例外が発生した場合。ネストしたfinallyブロック内で例外がスローされた場合は、finallyも途中で終了する可能性があります。コンパイラは、finallyブロックが正常に完了しなかったこと、またはアクセスできないコードがあることを示すエラーを出したことを警告します。到達不能コードのエラーは、throwが条件文の後ろまたはループの内側にない場合にのみ表示されます。
try{
}finally{
try{
}finally{
//if(someCondition) --> no error because of unreachable code
throw new RunTimeException();
}
int a = 5;//unreachable code
}
最後はいつも最後に呼ばれる
試してみると、何らかのコードが実行されます。tryで何か問題が発生した場合は、catchがその例外をキャッチし、mssgを出力するかエラーをスローして、最後にblockを実行します。
たとえば、Javaでスキャナーを使用する場合は、スキャナーを閉じる必要があります。ファイルを開けないなどの他の問題が発生する可能性があるためです。
tryブロックにreturn文を入れても、最後にblockは常に実行されます。 finallyブロックはreturn文の前に実行されます。
Finallyブロックをバイパスできる条件を次に示します。
最後のデーモン以外のスレッドの例:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
出力:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive