web-dev-qa-db-ja.com

catchおよびfinally節でスローされた例外

大学の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がどこに行くのかわかりません。

143
Jubstuff

あなたの答えを読んで、どうやってそれを思いついたのかを見ると、「進行中の例外」には「優先順位」があると思います。留意してください:

ブロックから伝播するcatchブロックまたは最後にblockで新しい例外がスローされると、現在の例外は中止されます(そして忘れられた)新しい例外は外側に伝播されます。新しい例外は他の例外と同じようにスタックの巻き戻しを開始し、現在のブロック(catchまたはfinallyブロック)から打ち切り、該当するcatchまたはfinallyブロックに沿って方法

適用可能なcatchまたはfinallyブロックには以下が含まれます:

catchブロックで新しい例外がスローされた場合、新しい例外は、catchのfinallyブロックが存在する場合でも引き続きブロックされます。

ここで、throwを押すたびに、現在の例外のトレースを中止し、新しい例外のトレースを開始する必要があることを思い出して、実行を再トレースします。

150
Bert F

これが 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例外がスローされます。 MyExc1public static void main(...)メソッドによって処理されます。

出力:

「スレッドメインMyExc1の132Exception」

講師は正しいです! :-)

本質的に、try/catch句にfinallyがある場合、finallyが実行されます(after例外をキャッチbeforeキャッチされた例外をスロー)

38
Buhake Sindi

JLS 11からの引用:14.20.2。 try-finallyおよびtry-catch-finallyの実行

Catchブロックが理由Rで突然完了した場合、finallyブロックが実行されます。次に、選択肢があります。

  • Finallyブロックが正常に完了すると、理由Rによりtryステートメントが突然完了します。

  • 最終ブロックが理由Sで突然終了した場合、tryステートメントは理由Sで突然終了します(そして、理由Rは破棄されます)。

33
Roland

最後の節は、try/catchブロックのどこからでも例外がスローされた場合でも実行されます。

mainで最後に実行され、例外をスローするため、呼び出し元に表示される例外です。

したがって、finally節は例外を飲み込む可能性があるため、try節が何もスローしないようにすることが重要です。

21

methodは2つの例外を同時にthrowすることはできません。常に最後にスローされたexceptionをスローします。この場合、これは常にfinallyブロックからのものです。

メソッドq()からの最初の例外がスローされると、最後にスローされた例外によってキャッチされ、その後飲み込まれます。

q() -> thrown new Exception->maincatch Exception->thrownew Exception->finally throw a new exception (and the one from the catch is "lost")

9
Garis M Suero

これを考える最も簡単な方法は、現在の例外を保持しているアプリケーション全体にグローバルな変数があると想像することです。

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
}
4
CodingWithSpike

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!";

}
////////////////////////////////////////////////// 
1
Sly
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)

https://www.compilejava.net/

0
Luiz Fernando

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が実行されます例外をキャッチした後ですが、スローする前にキャッチされた例外、最後にのみ例外がスローされます

0
yyFred

この種の状況、つまり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"
0
user8203210

finallyブロックを歩く必要があると思います。

  1. 「1」を印刷します。
  2. finally in qは「3」を印刷します。
  3. finally in mainは「2」を印刷します。
0
Uwe Keim