キャッチブロック内でスローされた例外-再びキャッチされますか?


180

これはプログラミング101の質問のように思えるかもしれませんが、私は答えを知っていると思っていましたが、今度は自分自身を再確認する必要があることに気づきました。以下のこのコードでは、最初のcatchブロックでスローされた例外は、以下の一般的なException catchブロックによってキャッチされますか?

try {
  // Do something
} catch(IOException e) {
  throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
  // Will the ApplicationException be caught here?
}

私はいつも答えはノーだと思っていましたが、今これによって引き起こされる可能性のある奇妙な行動があります。答えはおそらくほとんどの言語で同じですが、私はJavaで作業しています。


2
多分あなたは「奇妙な行動」を説明できますか?
ジェフリーLホイットリッジ

ApplicationExceptionが他の場所にスローされておらず、このブロックまで伝播していないことを確認しますか?
だらしない2008

私のEclipse IDEでこれに気づきました。「throw new Exception」をtryブロックに入れるように強制するのは面倒ですが、理由はわかりません。私はそれをせずに過去にそれをしたことがあります。tryブロックが必要になる理由がわかりません。グーグルの例の多くは、トライブロックを必要としない人々を示しています。それは私がifステートメントの内部を投げているからですか?
djangofan 2013

回答:


214

いいえ、新しいものthrowtry直接ブロックされていません。


コードが次のようになっているとしましょう{} catch(例外e){System.err.println( "In catch Exception:" + e.getClass()); } catch(IOException e){System.err.println( "In catch IOException:" + e.getClass()); }そしてtryブロックのコードはIO Exceptionを生成します。それはすぐに一般的なExceptionブロックに行きますか、それともIOException catchブロックに飛びますか?
sofs1

4
@ user3705478このような誤った状況を回避するために、コードはコンパイルされません。一般に、同じtryブロックでスーパークラスのキャッチの後にサブクラスのキャッチを行うことはできません。
Chris Jester-Young

ありがとう。だから、コンパイル時のエラーが出ますよね?家に着いたらテストします。
sofs1

これは@ user3705478に依存します。ブロックRuntimeExceptionからがスローされてcatchも、コンパイルエラーは発生しません。
Randy the Dev 2016年

@AndrewDunnこれは、user3705478の質問に関するものではないと思いますが、親例外catch句が子例外句の前にリストされている場合はどうなりますかcatch。私の理解では、Javaはこれを許可せず、コンパイル時に捕捉されます。
Chris Jester-Young

71

いいえ。確認は非常に簡単です。

public class Catch {
    public static void main(String[] args) {
        try {
            throw new java.io.IOException();
        } catch (java.io.IOException exc) {
            System.err.println("In catch IOException: "+exc.getClass());
            throw new RuntimeException();
        } catch (Exception exc) {
            System.err.println("In catch Exception: "+exc.getClass());
        } finally {
            System.err.println("In finally");
        }
    }
}

印刷する必要があります:

キャッチIOException:クラスjava.io.IOException
いよいよ
スレッド「メイン」の例外java.lang.RuntimeException
        Catch.main(Catch.java:8)で

技術的には、コンパイラのバグ、実装に依存する、不特定の動作などが考えられます。ただし、JLSはかなりうまく機能しており、コンパイラーはこの種の単純なことには十分対応できます(ジェネリックのコーナーケースは別の問題かもしれません)。

また、2つのcatchブロックを入れ替えても、コンパイルされません。2番目の漁獲量は完全に到達不可能です。

catchブロックが実行された場合でも、finallyブロックは常に実行されることに注意してください(無限ループ、ツールインターフェイスを介した接続、スレッドの強制終了、バイトコードの書き換えなどのばかげた場合を除く)。


3
を回避する最も明白な方法finallyは、もちろん、を呼び出すことSystem.exitです。:-P
クリスジェスター-ヤング

3
@Chris Jester-Young for(;;);は短く、言語内に含まれており、副作用の点であまり導入されていません。私にとっては、より明白です。
トム・ホーティン-タックライン

1
System.exitCPUに優しい!:-Oしかし、はい、わかりました、明らかにこれは主観的な基準です。また、あなたがコードゴルファーであることを知りませんでした。;-)
Chris Jester-Young、

28

Java言語仕様はセクション14.19.1で述べています:

値Vがスローされたためにtryブロックの実行が突然完了した場合は、選択肢があります。

  • Vの実行時の型がtryステートメントのいずれかのcatch句のパラメーターに割り当て可能な場合、最初(左端)のそのようなcatch句が選択されます。値Vが選択されたcatch節のパラメーターに割り当てられ、そのcatch節のBlockが実行されます。そのブロックが正常に完了すると、tryステートメントは正常に完了します。そのブロックが何らかの理由で突然完了した場合、tryステートメントは同じ理由で突然完了します。

リファレンス:http : //java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#24134

言い換えると、例外を処理できる最初の囲んでいるキャッチが実行され、そのキャッチから例外がスローされた場合、それは元の試行の他のどのキャッチのスコープにも含まれないため、処理しようとしません。

関連して混乱することの1つは、try- [catch] -finally構造では、finallyブロックが例外をスローする可能性があり、その場合、tryまたはcatchブロックによってスローされた例外はすべて失われることです。初めて見ると混乱するかもしれません。


Java 7以降、それを追加したかっただけですが、try-with-resources を使用することは避けてください。次に、tryANDとfinallyスローの両方finallyが抑制された場合は抑制されますが、からの例外にも追加されますtrycatch同様にスローする場合、「addSuppressed」を介して自分で処理し、try例外を追加しない限り、運はありません。3 つすべてが揃っています。
LAFKは2015

6

catchブロックから例外をスローする場合は、メソッド/クラスなどに通知する必要があります。上記の例外をスローする必要があること。そのようです:

public void doStuff() throws MyException {
    try {
        //Stuff
    } catch(StuffException e) {
        throw new MyException();
    }
}

そして今、あなたのコンパイラはあなたに怒鳴りません:)


4

いいえ-Chris Jester-Youngが言ったように、階層内の次のtry-catchまでスローされます。


2

上で述べたよう
に、何が起こっているのかがわからない場合、デバッガで問題を再現できない場合は、新しい例外を再スローする前にトレースを追加できます(古き良きシステム悪いことに.out.println、それ以外はlog4jのような優れたログシステム。


2

2番目のcatchブロックではキャッチされません。各例外は、tryブロック内でのみキャッチされます。ただし、試行を入れ子にすることもできます(一般的には、これは良いことではありません)。

try {
    doSomething();
} catch (IOException) {
   try {
       doSomething();
   } catch (IOException e) {
       throw new ApplicationException("Failed twice at doSomething" +
       e.toString());
   }          
} catch (Exception e) {
}

私は同様のコードを書きました。しかし、私は確信していません。catchブロックでThread.sleep()を呼び出したいのですが。しかし、Thread.sleepはそれ自体にInterruptedExceptionをスローします。あなたがあなたの例で示したようにそれをすることは正しい(ベストプラクティス)ですか?
riroo 2017年

1

いいえ、すべてのキャッチが同じtryブロックを参照しているため、catchブロック内からのスローは、(おそらくこれを呼び出したメソッド内の)囲んでいるtryブロックによってキャッチされます。


-4

古い投稿ですが、「e」変数は一意である必要があります:

try {
  // Do something
} catch(IOException ioE) {
  throw new ApplicationException("Problem connecting to server");
} catch(Exception e) {
  // Will the ApplicationException be caught here?
}

5
これはコメントであり、回答ではありません。それは実際の質問に対処する方法で何も提供しません-それは単にOPの質問の批評です。
Derek W
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.