catchの順序

このレッスンでできるようになること。catch を並べる順番だけでコンパイルエラーになる形と、マルチキャッチが使えない形を、見た瞬間に判定できるようになります。

まず予測してください

try { Integer.parseInt("abc"); } catch (Exception e) { System.out.println("広い"); } catch (NumberFormatException e) { System.out.println("狭い"); }

これは実行されません。コンパイルエラーです。2つめの catch には絶対に到達できないからです。1つめの Exception が NumberFormatException も含めて全部さらってしまうので、後ろの catch は死んだコードになります。Java はこれを「例外 NumberFormatException はすでに捕捉されています」として拒否します。

規則は2つだけ

  1. catch は上から順に「この型に代入できるか」で判定されます。最初に当てはまった1つだけが実行されます
  2. 上の catch の型が下の catch の型のスーパークラスなら、下は到達不能なのでコンパイルエラーです

したがって catch は狭い型から広い型へ並べます。逆は書けません。並びが兄弟同士(継承関係が無い型同士)なら、どちらが先でも構いません。ここも狙われます。IllegalArgumentException と IllegalStateException は兄弟なので順序は自由です。

マルチキャッチの落とし穴

複数の型をまとめて1つの catch で受けられます。

catch (IllegalArgumentException | IllegalStateException e) { }

これは通ります。しかし次はコンパイルエラーです。

catch (IllegalArgumentException | NumberFormatException e) { }

NumberFormatException は IllegalArgumentException のサブクラスです。マルチキャッチに継承関係のある型を並べることはできません。片方が余分だからです。もうひとつ、マルチキャッチの変数 e は暗黙に final なので、catch の中で e に別の例外を代入し直すこともできません。

覚えておきたい階層

NumberFormatException は IllegalArgumentException の子で、IllegalArgumentException と IllegalStateException は RuntimeException の子です。この3段を頭に入れておくと、順序問題はほぼ落としません。

確かめる

演習では、この3つを投げ分けるメソッドを狭い順に受け止めます。マルチキャッチも1つ使います。並べ替えてわざとエラーにしてみると、コンパイラの言い分が読めて記憶に残ります。

要件

  1. catch は NumberFormatException を先に書く
  2. IllegalArgumentException と IllegalStateException は1つのマルチキャッチで受ける
  3. NumberFormatException のときは "NFE" を返す
  4. マルチキャッチでは e.getClass().getSimpleName() を返す
  5. 例外が出なければ "OK " + 値 を返す

入出力例

pick(1)"NFE" pick(2)"IllegalArgumentException" pick(3)"IllegalStateException" pick(4)"OK 40"

ヒント

生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア
編集 LuaGate編集部
main.java
学習モード

メモ

catchの順序

⌘S で保存