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


155

大学の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行くのか理解できません。

回答:


167

あなたの答えを読んで、どのようにしてそれを思い付いたかを見ると、「例外処理中」には「優先順位」があると思います。覚えておいてください:

新しい例外がcatchブロックまたは最終的にそのブロックの外に伝播するブロックでスローされると、新しい例外が外側に伝播されるため、現在の例外は中止(および忘れられます)されます。新しい例外は、他の例外と同じようにスタックの巻き戻しを開始し、現在のブロック(catchまたはfinallyブロック)を中止して、途中で該当するcatchまたはfinallyブロックの対象になります。

適用可能なcatchまたはfinallyブロックには以下が含まれることに注意してください。

新しい例外がcatchブロックでスローされた場合、新しい例外は、もしあれば、そのcatchの最終ブロックの影響を受けます。

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


7
まさに私の考えだったありがとう... :)«あなたの答えを読んで、あなたはおそらくそれを思い付いたのか見に基づいて、私はあなたが『例外進行中』 『優先』持っていると思うと信じ»
Jubstuff

39

これはウィキペディアが最終的に節について言っていることです:

より一般的なのは、例外が発生したかどうかに関係なく実行される関連句(最終的に、または確実)です。通常、例外処理ブロックの本体内で取得されたリソースを解放します。

プログラムを分析してみましょう。

try {
    System.out.print(1);
    q();
}

そのため1、画面に出力されてからq()呼び出されます。ではq()、例外がスローされます。その後、例外はキャッチされますException yが、何もしません。最後に句は、次に(それがなければならない)が実行されるので、3画面に出力されます。(メソッドq()では、finally節で例外がスローされるため、q()メソッドは(throws Exceptionメソッド宣言で)親のスタックに例外を渡し、によってnew Exception()スローおよびキャッチされるためcatch ( Exception i )MyExc2例外がスローされます(今のところ、例外スタックに追加します) )、ただしブロックの最終的にはmain最初に実行されます。

だから、

catch ( Exception i ) {
    throw( new MyExc2() );
} 
finally {
    System.out.print(2);
    throw( new MyExc1() );
}

最後に句は(覚えて、私達はちょうどキャッチしました...と呼ばれているException iとスローMyExc2)本質的に、2画面上に印刷されて...と後に2画面上に印刷され、MyExc1例外がスローされます。メソッドMyExc1によって処理されpublic static void main(...)ます。

出力:

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

講師は正解です!:-)

本質的にはあなたが持っている場合は、最終的にはのtry / catch節では、最終的には、(実行されます、例外をキャッチする前にキャッチされた例外を投げ)


catch以降が実行されるq()投げたException独自のfinallyブロック。
ペーテルTörök

"q()では、例外がスローされますが、例外が完全にスローされる前に、finally句が最初に実行されるため、3が画面に出力されます。"ええと...いいえ、最初にスローされた例外qは実行を空のcatchブロックq(この例外を飲み込む)、次にのfinallyブロックへq。最終的にはプリントをブロックすると述べ3、その後のおかげで新しい例外、スローqのがthrows Exception親にスタックを渡されています。
Powerlord 2010

38

finallyブロックの例外は、catchブロックの例外に優先します。

Java言語仕様14版からの引用:

理由Rのためにcatchブロックが突然完了すると、finallyブロックが実行されます。次に選択肢があります:

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

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


21

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

これはで最後に実行されてmain例外をスローするため、呼び出し元が見る例外です。

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


5
try / catchブロックで例外がスローされない場合でも実行されます
nanda

2
+1:OPがすでに理解しているように見えるスタック全体を蛇行させずに、直接、要点を定めます。
Powerlord 2010

9

A methodできませんthrow、同時に2つの例外。常に最後にスローされたをスローexceptionfinallyます。この場合、常にブロックからのスローになります。

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

q()->スローnew Exception -> main catch Exception -> throw new Exception -> finally新しいスローexception(およびの1つcatchが「失われた」)


3

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

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
}

1

最終ブロックは、try and catchの後に実行され、常に実行されることはよく知られています。しかし、少し注意が必要な場合があるので、以下のコードスニペットを確認すると、returnステートメントとthrowステートメントが実行されません。常に彼らがすべきことを、私たちがテーマを期待する順序で実行するわけではありません。

乾杯。

/////////////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
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/


1
このコードスニペットが解決策となる可能性がありますが、説明を含めると、投稿の品質向上に役立ちます。あなたが将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません
Rahul Gupta

1

印刷が完了するまで、ロジックは明確13です。次に、スローされた例外がin q()によってキャッチさcatch (Exception i)main()、aをnew MyEx2()スローする準備が整います。ただし、例外をスローする前に、finallyブロックを最初に実行する必要があります。次に、出力はになり132finally別の例外のスローを要求しますnew MyEx1()

メソッドは複数をスローできないため、Exception常に最新のものをスローしExceptionます。つまり、catchfinallyブロックの両方がをスローしようとするとExceptionExceptionインキャッチが飲み込まれ、例外のみfinallyがスローされます。

したがって、このプログラムでMyEx2は、例外が飲み込まれMyEx1てスローされます。この例外はスローされ、main()キャッチされなくなったため、JVMは停止し、最終出力はになり132Exception in thread main MyExc1ます。

あなたが持っている場合は本質的には、finallytry/catch節、finally実行される例外をキャッチAFTERが、任意のキャッチされた例外をスローする前に唯一の最新の例外が最後にスローされます


0

私はあなたがfinallyブロックを歩く必要があると思います:

  1. 「1」を印刷します。
  2. finallyq「3」のプリント。
  3. finallymain「2」のプリント。

0

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

-1

私はこれで問題が解決すると思います:

boolean allOk = false;
try{
  q();
  allOk = true;
} finally {
  try {
     is.close();
  } catch (Exception e) {
     if(allOk) {
       throw new SomeException(e);
     }
  }
}

3
どのような問題を「解決」しますか?試験の問題ですか?まあそれはすでに答えました。与えられたコードの問題を意味する場合、それは単なる試験問題なので、それを非難する意味はありません。
Earth Engine
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.