yohhoyの日記

技術的メモをしていきたい日記

複数例外catchの型推論

Java7で導入された複数例外 catch における型推論についてメモ。*1

下記コードでの multi-catch 節における変数eの静的型は、Javaコンパイラ型推論によりException & CustomException型となる。つまりExceptionクラスとCustomExceptionインタフェースの両者をスーパータイプとして持つ型として扱われる。また multi-catch 節の変数は暗黙にfinal宣言される。

interface CustomException {
  int getCustomInfo();
}

class MyException1 extends Exception implements CustomException {
  public int getCustomInfo() { return 1; }
}

class MyException2 extends Exception implements CustomException {
  public int getCustomInfo() { return 2; }
}

try {
  //...
} catch (MyException1 | MyException2 e) {
  String msg = e.getMessage();   // OK: Throwableインタフェースを実装
  int info = e.getCustomInfo();  // OK: CustomExceptionインタフェースを実装
  e = new MyException1();  // NG: error: multi-catch parameter e may not be assigned
}

Java言語仕様上は、multi-catch 節に記述した例外クラス群(MyException1, MyException2)のLeast Upper Bound*2型に推論される。実用上は「共通の最派生スーパークラスかつ共通のインタフェース群を実装する型」と解釈すれば良い。

Java Language Specification, Java SE 8 Editionより一部引用。*3

The least upper bound, or "lub", of a set of reference types is a shared supertype that is more specific than any other shared supertype (that is, no other shared supertype is a subtype of the least upper bound). This type, lub(U1, ..., Uk), is determined as follows.
(snip)

Chapter 4. Types, Values, and Variables, 4.10.4. Least Upper Bound

An exception parameter may denote its type as either a single class type or a union of two or more class types (called alternatives). The alternatives of a union are syntactically separated by |.
A catch clause whose exception parameter is denoted as a union of types is called a multi-catch clause.
The declared type of an exception parameter that denotes its type as a union with alternatives D1 | D2 | ... | Dn is lub(D1, D2, ..., Dn).
An exception parameter of a multi-catch clause is implicitly declared final if it is not explicitly declared final.

Chapter 14. Blocks and Statements, 14.20. The try statement

Java言語仕様に則った lub(MyException1, MyException2) の導出過程は下記の通り*4ジェネリクスが絡まなければ比較的簡単。

  • U1 = MyException1, U2 = MyException2
  • ST(U1) = EST(U1) = { Object, Throwable, Exception, CustomException, MyException1 }
  • ST(U2) = EST(U2) = { Object, Throwable, Exception, CustomException, MyException2 }
  • EC = { Object, Throwable, Exception, CustomException }
  • MEC = { Exception, CustomException }, G = {}
  • lub(U1, U2) = Exception & CustomException

関連URL

*1:https://twitter.com/yohhoy/status/774813224491294720 をきっかけに調べた内容。

*2:Java用語としては安定した対訳語は存在しない様子。直訳すると “最小の上限境界”。なお数学用語としては “上限”/“最小上界” が当てられるらしいが、Java的には“Upper Bound”=“上限境界”となっているので微妙。

*3:Java7仕様では15.12.2.7. Inferring Type Arguments Based on Actual Argumentsにてlubが定義される。

*4:ST(supertypes)集合はその元に自分自身を含む(reflexive)。JLS 8 4.10参照。