[Java] SonOfAnException Handling in Try Multi-Catch?

原文はこちら。
https://blogs.oracle.com/binkyscave/entry/sonofanexception_handling_in_try_multi

今月頭にJavaOne Indiaで講演していたところ、参加者からtry multi-catch構文について質問がありました。最初の質問は例外の処理順序に関する質問でしたが、その裏にある質問は、その例外が別の例外のサブクラスである場合はどうなるのか、また別の言い方をすれば、multi-catchは例外の息子を処理することができるのか、というものでした。
質問を受けたときに回答を持っていないのは嫌なので、ちょっと調べて正解を見つけました。明確にするため、以下のような状況について話しています。
try {
  throwAorSonOFA();
} catch(ExceptionA | SonOfExceptionA e) {
  ...
}
上記のような場合、ExceptionAが投げられるのでしょうか、それともtryの中でSonOfExceptionAが投げられる場合、SonOfExceptionAが捕獲されるのでしょうか。
答えはどちらでもありません。コンパイル中にコンパイル時エラーになってしまうのです。
答えを探すため、OpenJDK 7 Featuresに当たりはじめました。四分の一ほど進むと、Joe DarcyがリードしたSmall language enhancements(Project Coin)に関する記載があります。
JSR 334: Small language enhancements (Project Coin)
http://openjdk.java.net/projects/jdk7/features/#f618
Joseph D. Darcy's Oracle Weblog
https://blogs.oracle.com/darcy/
Joeのブログを見ていると、2011年5月24日のエントリにて、JDK 7 b143で実装されるProject Coinの機能のセマンティクスへのリンクがありました。
Project Coin: Documenation at Rampdown (Joseph D. Darcy's Oracle Weblog)
https://blogs.oracle.com/darcy/entry/project_coin_rampdown_documenation
Project Coin/JSR 334 Documentation v0.9375
http://cr.openjdk.java.net/~darcy/ProjectCoin/ProjectCoin-Documentation-v0.9375.html
この文書には、実装の背後にある理由がたくさん記載されています。具体的には、"Multi-catch and more precise rethrow"の構文セクションで以下のような文章があります。
A try statement may have catch clauses (also called exception handlers).
A catch clause must have exactly one parameter (which is called an exception  parameter); the declared type of the exception parameter can be a single 
class type or can be a union type (denoted with '|') between two or more 
class types (or alternatives). A catch clause with a union type parameter is called a multi-catch clause. For the purposes of type-checking, a union type D with alternatives D1, D2... Dn has type lub(D1, D2... Dn) (§15.12.2.7). It is a compile-time error if a union type contains two alternatives Di, Dj where Di is a subtype of Dj.
(tryステートメントにはcatch句(例外ハンドラと呼ばれることがあります)を含む場合があります。
catch句は厳密に一つのパラメータ(例外パラメータと呼ばれるものです)を持たなければなりません。例外パラメータの宣言型は単一のクラス型か、2個以上のクラス型のunion型(|を使って表記)をとることができます。
Union型を取るcatch句を、multi-catch句と呼びます。型チェックの目的のために、D1、D2...Dnという型のunion型Dはlub(D1, D2, ...Dn)という型を持ちます(§15.12.2.7)。
union型にDjとDjのサブタイプであるDiを含む場合、コンパイル時エラーになります。
)


15.12.2.7. Inferring Type Arguments Based on Actual Arguments
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.7
しかし、このドキュメントをそのまま信じるわけにはいかないので、Java Language Specification, SE 7 Edition(Java言語仕様 SE 7版)の14章の第20節を当たってみました。
The Java™ Language Specification Java SE 7 Edition
http://docs.oracle.com/javase/specs/jls/se7/html/index.htmlChapter 14. Blocks and Statements - 14.20. The try statement
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20
これはJava言語のバイブルですね。ここに太字で明確に書かれています。
It is a compile-time error if a union of types contains two alternatives Di and Dj (i ≠ j) where Di is a subtype of Dj (§4.10.2).
(DiがDjのサブタイプである場合、DiとDj(I≠j)という二つの選択肢を含んでいるとコンパイル時エラーになります)
あぁ、これですっきりしました。そして、元の質問に関連して、この行も見つけました。
If a value is thrown and the try statement has one or more catch clauses 
that can catch it, then control will be transferred to the first such catchclause.(値が投げられ、tryステートメントにその値を捕獲できる1個以上のcatch句がある場合は、最初のcatch句に制御が渡されます)
翻訳すると、例外を左から右への順序で試行します。一つわからなかったのは、mutli-catch例外処理がデフォルトでfinalである、ということです。仕様では、以下のようになっています。
An exception parameter of a multi-catch clause is implicitly declared final 
if it is not explicitly declared final. (multi-catch句の例外引数は、明示的にfinalで宣言しない場合、暗黙のうちにfinalで宣言されます)
そしてさらに少し下に、finalとして宣言したcatch句を使って同等のコードを表したmulti-catchの例があります。

まぁ、そんなわけですので、(少なくともmulti-catchに関する限り)例外のサブクラスを取り扱うことはありません。

0 件のコメント:

コメントを投稿