18

throwこのステートメント (より複雑なコードから抽出されたもの) がコンパイルされることに偶然気付きました。

void foo() {
    try {

    } catch (Throwable t) {
        throw t;
    }
}

短いながらも幸せな瞬間、私はチェック例外が最終的にすでに死ぬことを決定したと思っていましたが、それでもこれには満足しています:

void foo() {
    try {

    } catch (Throwable t) {
        Throwable t1 = t;
        throw t1;
    }
}

ブロックは空である必要はtryありません。そのコードがチェックされた例外をスローしない限り、コードを持つことができるようです。それは理にかなっているように思えますが、私の質問は、言語仕様のどの規則でこの動作が説明されているのでしょうか? 私が見る限り、§14.18 throw ステートメントは明示的に禁止しています。これは、式の型がtチェック済み例外であり、キャッチされていないか、スローされるように宣言されていないためです。(?)

4

3 に答える 3

13

これは、Java 7 で導入されたProject Coinに含まれていた変更により、元の例外の再スローによる一般的な例外処理が可能になったためです。以下は、Java 7 では機能するが Java 6 では機能しない例です。

public static demoRethrow() throws IOException {
    try {
        throw new IOException("Error");
    }
    catch(Exception exception) {
        /*
         * Do some handling and then rethrow.
         */
        throw exception;
    }
}

変更を説明する記事全体を読むことができますここ.

于 2014-07-27T14:10:52.590 に答える
8

あなたが参照している§14.18 The throwStatementの文言は、JLS の誤りであると思います — テキストは Java SE 7 で更新されるべきでしたが、そうではありませんでした。

意図した動作を説明する JLS テキストの一部は、§11.2.2 Exception Analysis of Statements にあります。

throwスローされた式が句 C の最終または実質的に最終の例外パラメーターであるステートメントは、次のcatch場合に例外クラス E をスローできます。

  • E は、 C を宣言するステートメントのtryブロックがスローできる例外クラスです。try
  • E は、C のキャッチ可能な例外クラスのいずれかと互換性のある代入です。と
  • E は、同じステートメントcatchで C の左側に宣言されている節のキャッチ可能な例外クラスのいずれとも代入互換性がありません。try

最初の箇条書きが関連するものです。catch-clause パラメーターは事実上 final であるためt(つまり、割り当てられたり、インクリメントまたはデクリメントされたりしないことを意味します。§4.12.4final変数を参照してください)、ブロックがスローthrow tできるものしかスローできません。try

しかし、あなたが言うように、§14.18 のコンパイル時チェックでは、これが考慮されていません。§11.2.2 は、何が許可され、何が許可されないかを決定しません。むしろ、スローできるものに対するさまざまな制限の結果を分析することになっています。(この分析は、仕様のより規範的な部分にフィードバックします — §14.18 自体は、2 番目の箇条書きでそれを使用しています — しかし、§14.18 は、「例外をスローする場合、それはコンパイル時エラーです。 §11.2.2" に従ってスローします。これは循環するためです。)

したがって、§11.2.2 の意図に対応するために、§14.18 を調整する必要があると思います。

良い発見!

于 2014-07-27T19:49:45.073 に答える