8

次の方法で調査します。

static private void foo()  {
        try {
            throw new FileNotFoundException();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

このコードは、最後の catch ブロックが実際には到達できないにもかかわらず、正常にコンパイルされます。

throw new FileNotFoundException();行にコメントしましょう

実行する:

おっと!私たちは見る

Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body

変。Java がこれらの状況で二重基準を使用するのはなぜですか?

@Peter Raderの更新

static private void foo(FileNotFoundException f)  {
        try {
            throw f;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

コンストラクター呼び出しと同様に機能します

アップデート

Javaコンパイラの異なるバージョンでは、このコードをコンパイルした結果が異なることに気付きました。

public class RethowTest {

        public static void main(String[] args)  {
            try {
                throw new FileNotFoundException();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                throw e;
            }
        }    
}

私のローカルPC上:Java 1.7.0_45 -

C:\Program Files\Java\jdk1.7.0_45\bin>javac D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java
D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:15: warning: unreachable catch clause
                } catch (IOException e) {
                  ^
  thrown type FileNotFoundException has already been caught
1 warning

ジャバ 1.6.0_38

D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown
                    throw e;
                    ^
1 error

http://www.compileonline.com/compile_java_online.php (Javac 1.7.0_09) -

HelloWorld.java:9: warning: unreachable catch clause
        } catch (IOException e) {
          ^
  thrown type FileNotFoundException has already been caught
1 warning
4

3 に答える 3

6

到達可能性ルールは、Java 8 JLS 14.21 (および Java 7) で次のように定義されています。

次の両方が true の場合、catch ブロック C に到達できます。

  • C のパラメーターの型がチェックされていない例外の型または Exception または Exception のスーパークラスであるか、try ブロック内の式または throw ステートメントが到達可能であり、その型が C のパラメーターの型に割り当て可能なチェック済みの例外をスローできます。(式は、それを含む最も内側のステートメントに到達できる場合に到達可能です。)

    式の通常の完了と突然の完了については、§15.6 を参照してください。

  • C のパラメーターの型が A のパラメーターの型と同じか、そのサブクラスであるような、try ステートメント内の以前の catch ブロック A はありません。

ルールはサンプル コードを禁止しないことに注意してください。2 番目の catch ブロックは、2 番目の箇条書きの基準を満たしていません。

(例の元のバージョンでは、 をキャッチしExceptionました。到達可能性の理由は異なりますが、答えは同じです - 有効なコードです。)

これは矛盾していますか?あなたの例では、そうであると主張できます。

到達可能性ルールでこのケースに対処しなかったのはなぜですか? 知らない。Java 設計者に聞く必要があります!! でも:

  • これを処理するには、到達可能性ルールの定式化を大幅に複雑にする必要があります。仕様の余分な (不必要な?) 複雑さは懸念事項です。

  • この矛盾は何も壊さないと主張することができます。到達可能性ルールは、実際には、ユーザー コードの潜在的なエラーを検出する方法にすぎません。タイプセーフまたは予測可能な実行は含まれません。つまり、Java ランタイムのセマンティクスを「壊す」ものです。

  • 彼らが今仕様を変更した場合、有効で機能しているJavaプログラムのごく一部が無効になります。安定性が Java の主要なセールス ポイントの 1 つであることを考えると、これは良い考えではありません。

一方で、仕様のこの「矛盾」に対処できなかった技術的な理由は思いつきません。


一部の Java コンパイラは 2 番目に警告メッセージを表示することに注意してくださいcatch。それは大丈夫です。Java コンパイラは、(技術的に) 正当な Java コードに対して警告を発することが許可されています。

それらがエラーである場合、それは技術的にはコンパイラのバグです... JLSを読んだところによると。

于 2014-09-02T22:52:58.847 に答える
1

ブロックはcatch (Exception ...)実行時例外をキャッチします。原則として到達できないことはありません。

FileNotFoundExceptionチェック例外です。そのための catch ブロックは、try ブロック内の何かがそれをスローするか、その子クラスの 1 つがスローされた場合にのみ到達可能です。

【ご要望にお応えして】

于 2014-09-02T23:53:36.510 に答える
-3

インスタンス化する場合new FileNotFoundException()は、 Class のコンストラクターを呼び出しますFileNotFoundException。このコンストラクターでは、理論上、ネイティブ メソッドを呼び出すことで IOException をスローできますfillInStackTrace。コンパイラーはコンストラクターの内容を認識していない可能性があり、おそらく aIOExceptionがスローされます。

この記事を参照してください: https://community.oracle.com/thread/1445008?start=0例。

コンパイラがFileNotFoundException()発生ごとにコンストラクタを調べると、Java のオーバーヘッドがパフォーマンスを無視します。

于 2014-09-02T13:28:05.313 に答える