検査例外と非検査例外

このレッスンでできるようになること。throws を書かないとコンパイルが通らない例外と、書かなくても通る例外を、その場で見分けられるようになります。

まず予測してください

次の2つのメソッドのうち、コンパイルできるのはどちらでしょうか。

static int a(String s) { return Integer.parseInt(s); // NumberFormatException が飛ぶ可能性がある } static int b(String s) { throw new java.io.IOException("だめ"); // IOException が飛ぶ }

答えは a だけです。b は「例外 IOException は報告されません」というコンパイルエラーになります。どちらも例外を投げうるのに、片方だけ怒られます。この差が Silver の頻出ポイントです。

境目は RuntimeException と Error

Java の例外はすべて Throwable の子孫です。その下は大きく3つに分かれます。

  • Error とその子孫(OutOfMemoryError など)は非検査例外です
  • RuntimeException とその子孫(NullPointerException、NumberFormatException、IllegalArgumentException、ArrayIndexOutOfBoundsException など)は非検査例外です
  • それ以外の Exception の子孫(IOException、SQLException、そして自作の「Exception を継承した例外」)は検査例外です

検査例外は「投げる可能性があるなら、その場で catch するか、メソッドに throws と書いて呼び出し元に押しつけるか、どちらかをやりなさい」とコンパイラが強制します。非検査例外にはこの強制がありません。

引っ掛けの作り方

出題者は次の形を好みます。

  1. 自作例外に extends Exception と書いて、呼び出し側で何もしない。検査例外なのでコンパイルエラーです
  2. 自作例外に extends RuntimeException と書いて、throws が無いのを「エラーだ」と思わせる。こちらは正しく通ります
  3. throws が付いたメソッドを try で囲んでいるが、catch している型が検査例外の親でもなんでもない。やはりコンパイルエラーです

覚え方は「名前に Runtime か Error が入る血筋なら自由、それ以外の Exception の血筋なら申告が要る」です。

確かめる

演習では、検査例外と非検査例外の両方が飛びうるメソッドを1つの try で受け止め、飛んできた例外のクラス名を返します。catch (Exception e) は検査例外も非検査例外もまとめて捕らえられます。実行して、同じ書き方で両方が捕まることを目で確認してください。

要件

  1. parse(s) の呼び出しを try で囲み、catch (Exception e) で受け止める
  2. 成功したときは "OK " + 値 を返す
  3. 例外が飛んだときは e.getClass().getSimpleName() を返す
  4. parse と EmptyInputException には手を加えない

入出力例

check("12")"OK 12" check("")"EmptyInputException" check("abc")"NumberFormatException"

ヒント

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

メモ

検査例外と非検査例外

⌘S で保存