大学のJavaに対する質問には、次のコードスニペットがありました。
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
public static void main(String[] args) throws Exception {
try {
System.out.print(1);
q();
}
catch (Exception i) {
throw new MyExc2();
}
finally {
System.out.print(2);
throw new MyExc1();
}
}
static void q() throws Exception {
try {
throw new MyExc1();
}
catch (Exception y) {
}
finally {
System.out.print(3);
throw new Exception();
}
}
}
その出力を提供するように頼まれました。 13Exception in thread main MyExc2
と答えましたが、正しい答えは132Exception in thread main MyExc1
です。それはなぜですか? MyExc2がどこに行くのかわかりません。
あなたの答えを読んで、どうやってそれを思いついたのかを見ると、「進行中の例外」には「優先順位」があると思います。留意してください:
ブロックから伝播するcatchブロックまたは最後にblockで新しい例外がスローされると、現在の例外は中止されます(そして忘れられた)新しい例外は外側に伝播されます。新しい例外は他の例外と同じようにスタックの巻き戻しを開始し、現在のブロック(catchまたはfinallyブロック)から打ち切り、該当するcatchまたはfinallyブロックに沿って方法
適用可能なcatchまたはfinallyブロックには以下が含まれます:
catchブロックで新しい例外がスローされた場合、新しい例外は、catchのfinallyブロックが存在する場合でも引き続きブロックされます。
ここで、throw
を押すたびに、現在の例外のトレースを中止し、新しい例外のトレースを開始する必要があることを思い出して、実行を再トレースします。
これが Wikipedia がfinally節について言っていることです:
より一般的なのは、例外が発生したかどうかに関係なく実行され、通常は例外処理ブロックの本体内で取得したリソースを解放する関連句(最終的に、または確認)です。
プログラムを分析してみましょう。
try {
System.out.print(1);
q();
}
したがって、1
が画面に出力され、q()
が呼び出されます。 q()
では、例外がスローされます。例外はException y
によってキャッチされますが、何もしません。 finally句が実行されます(実行する必要があります)。そのため、3
が画面に出力されます。 (メソッドq()
にはfinally句で例外がスローされるため、q()
メソッドも例外を親スタックに渡します(throws Exception
メソッド宣言で)new Exception()
がスローされ、catch ( Exception i )
によってキャッチされ、MyExc2
例外がスローされます(現時点では例外スタックに追加されます)が、finallymain
ブロック内の最初に実行されます。
だから、
catch ( Exception i ) {
throw( new MyExc2() );
}
finally {
System.out.print(2);
throw( new MyExc1() );
}
finally句が呼び出されます...(覚えておいて、Exception i
をキャッチし、MyExc2
をスローしただけです、 2
が画面に出力されます...そして2
が画面に出力された後、MyExc1
例外がスローされます。 MyExc1
はpublic static void main(...)
メソッドによって処理されます。
出力:
「スレッドメインMyExc1の132Exception」
講師は正しいです! :-)
本質的に、try/catch句にfinallyがある場合、finallyが実行されます(after例外をキャッチbeforeキャッチされた例外をスロー)
JLS 11からの引用:14.20.2。 try-finallyおよびtry-catch-finallyの実行
Catchブロックが理由Rで突然完了した場合、finallyブロックが実行されます。次に、選択肢があります。
Finallyブロックが正常に完了すると、理由Rによりtryステートメントが突然完了します。
最終ブロックが理由Sで突然終了した場合、tryステートメントは理由Sで突然終了します(そして、理由Rは破棄されます)。
最後の節は、try/catchブロックのどこからでも例外がスローされた場合でも実行されます。
main
で最後に実行され、例外をスローするため、呼び出し元に表示される例外です。
したがって、finally
節は例外を飲み込む可能性があるため、try
節が何もスローしないようにすることが重要です。
method
は2つの例外を同時にthrow
することはできません。常に最後にスローされたexception
をスローします。この場合、これは常にfinally
ブロックからのものです。
メソッドq()
からの最初の例外がスローされると、最後にスローされた例外によってキャッチされ、その後飲み込まれます。
q() -> thrown new Exception
->main
catch Exception
->throw
new Exception
->finally
throw a new exception
(and the one from the catch
is "lost")
これを考える最も簡単な方法は、現在の例外を保持しているアプリケーション全体にグローバルな変数があると想像することです。
Exception currentException = null;
各例外がスローされると、「currentException」がその例外に設定されます。アプリケーションが終了し、currentExceptionが!= nullの場合、ランタイムはエラーを報告します。
また、finallyブロックは、メソッドが終了する前に常に実行されます。次に、コードスニペットを次のように繰り返すことができます。
public class C1 {
public static void main(String [] argv) throws Exception {
try {
System.out.print(1);
q();
}
catch ( Exception i ) {
// <-- currentException = Exception, as thrown by q()'s finally block
throw( new MyExc2() ); // <-- currentException = MyExc2
}
finally {
// <-- currentException = MyExc2, thrown from main()'s catch block
System.out.print(2);
throw( new MyExc1() ); // <-- currentException = MyExc1
}
} // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console.
static void q() throws Exception {
try {
throw( new MyExc1() ); // <-- currentException = MyExc1
}
catch( Exception y ) {
// <-- currentException = null, because the exception is caught and not rethrown
}
finally {
System.out.print(3);
throw( new Exception() ); // <-- currentException = Exception
}
}
}
アプリケーションが実行される順序は次のとおりです。
main()
{
try
q()
{
try
catch
finally
}
catch
finally
}
Finallyブロックがtry and catchの後に実行され、常に実行されることはよく知られています。 '私たちが期待する順序で彼らがすべきことをいつもするわけではない。
乾杯。
/////////////Return dont always return///////
try{
return "In Try";
}
finally{
return "In Finally";
}
////////////////////////////////////////////
////////////////////////////////////////////
while(true) {
try {
return "In try";
}
finally{
break;
}
}
return "Out of try";
///////////////////////////////////////////
///////////////////////////////////////////////////
while (true) {
try {
return "In try";
}
finally {
continue;
}
}
//////////////////////////////////////////////////
/////////////////Throw dont always throw/////////
try {
throw new RuntimeException();
}
finally {
return "Ouuuups no throw!";
}
//////////////////////////////////////////////////
class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
public static void main(String[] args) throws Exception {
try {
System.out.print("TryA L1\n");
q();
System.out.print("TryB L1\n");
}
catch (Exception i) {
System.out.print("Catch L1\n");
}
finally {
System.out.print("Finally L1\n");
throw new MyExc1();
}
}
static void q() throws Exception {
try {
System.out.print("TryA L2\n");
q2();
System.out.print("TryB L2\n");
}
catch (Exception y) {
System.out.print("Catch L2\n");
throw new MyExc2();
}
finally {
System.out.print("Finally L2\n");
throw new Exception();
}
}
static void q2() throws Exception {
throw new MyExc1();
}
}
注文:
TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1
Exception in thread "main" MyExc1 at C1.main(C1.Java:30)
13
の出力が完了するまで、ロジックは明確です。次に、q()
でスローされた例外は、catch (Exception i)
のmain()
によってキャッチされ、new MyEx2()
をスローする準備ができました。ただし、例外をスローする前に、finally
ブロックを最初に実行する必要があります。次に、出力は132
になり、finally
は別の例外new MyEx1()
をスローするように要求します。
メソッドは複数のException
をスローできないため、常に最新のException
をスローします。つまり、catch
ブロックとfinally
ブロックの両方がException
をスローしようとした場合、catchのException
はですswallowedそしてfinally
の例外のみがスローされます。
したがって、このプログラムでは、例外MyEx2
が飲み込まれ、MyEx1
がスローされます。この例外はmain()
からスローされ、キャッチされなくなったため、JVMは停止し、最終出力は132Exception in thread main MyExc1
になります。
本質的に、try/catch
句にfinally
がある場合、finally
が実行されます例外をキャッチした後ですが、スローする前にキャッチされた例外、、最後にのみ例外がスローされます。
この種の状況、つまりfinallyブロックによって発生した例外を処理するため。 tryブロックでfinallyブロックを囲むことができます:Pythonの次の例を見てください:
try:
fh = open("testfile", "w")
try:
fh.write("This is my test file for exception handling!!")
finally:
print "Going to close the file"
fh.close()
except IOError:
print "Error: can\'t find file or read data"
finally
ブロックを歩く必要があると思います。
finally
in q
は「3」を印刷します。finally
in main
は「2」を印刷します。