1. ホーム
  2. java

[解決済み] Java 8 の例外型推論における特異な機能

2023-04-26 11:59:14

質問

このサイトの別の回答のためにコードを書いているとき、私はこの奇妙なことに遭遇しました。

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    //no problems here
  nonSneakyThrow(e); //ERRROR: Unhandled exception: java.lang.Exception
}

@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static <T extends Throwable> void nonSneakyThrow(T t) throws T {
  throw t;
}

まず、なぜ sneakyThrow の呼び出しがコンパイラにOKされるのか、かなり混乱しています。コンパイラはどのような可能性のある型を T に対してどのような型を推測したのでしょうか?

第二に、これがうまくいくとして、なぜコンパイラは nonSneakyThrow の呼び出しで文句を言うのでしょうか?それらは非常によく似ているように見えます。

どのように解決するのですか?

のTは sneakyThrow であることが推論されます。 RuntimeException . これは,型推論に関する言語仕様から導かれます ( http://docs.oracle.com/javase/specs/jls/se8/html/jls-18.html )

まず、18.1.3節に注釈があります。

という形式のバウンド throws α は純粋に情報的なもので、可能であればチェックされる例外型にならないようにαのインスタンス化を最適化するよう解決を指示します。

これは何も影響しませんが、解決セクション(18.4)を指し示し、特別なケースで推測される例外型に関するより多くの情報を持っています。

... そうでなければ、もしバインドセットに throws αi であり、αi の適切な上界は、最大でも Exception , Throwable そして Object であるならば、Ti = RuntimeException .

このケースに該当するのは sneakyThrow - に適用され、唯一の上限は Throwable であり、したがって T が推論されます。 RuntimeException であると推測され、コンパイルされます。メソッドの本体は重要ではありません。チェックされていないキャストは実際には起こらないので実行時に成功し、コンパイル時にチェックされる例外システムを破ることができるメソッドを残します。

nonSneakyThrow はコンパイルされないので、そのメソッドの T の下限が Exception (つまり T のスーパータイプでなければなりません。 Exception のスーパータイプでなければなりません。 Exception 自体) で呼び出されるタイプによってチェックされた例外となるので T として推論されます。 Exception .