🚨

Javaのチェック例外/非チェック例外の使い分け?

に公開
2

例外クラスの継承構造

Javaにおいては、例外はクラスです。こんな感じの継承構造になっています。

例外クラスの継承構造
この図はイメージ優先のため、正確な継承構造ではありません。

一番上のスーパークラスはThrowableです(Objectのサブクラス)。

ThrowableのサブクラスはExceptionErrorです。

Errorおよびそのサブクラスは、メモリが足りないなどかなり致命的な例外です。基本的には、これらがスローされたらアプリケーションを止めるしかありません。

Exceptionのサブクラスは、RuntimeExceptionおよびそのサブクラスと、RuntimeException以外のサブクラスに分かれます。

チェック例外と非チェック例外の文法上の分類

例外にはチェック例外と非チェック例外があります。

  • 非チェック例外
    • Errorおよびそのサブクラス、RuntimeExceptionおよびそのサブクラス
    • try-catchやthrows句を書かなくてもよい(書いてもよい)
  • チェック例外
    • 非チェック例外以外の全ての例外
    • try-catchやthrows句を書く必要がある(書かないとコンパイルエラー)

つまり「チェック」というのは、コンパイラーによるチェックなんですね。

チェック例外と非チェック例外の使い分け基準?

Javaの入門書などでよく言われる使い分け基準が以下です。

  • 「チェック例外は、ファイルシステムやネットワークなど外部の要因で発生する」
  • 「非チェック例外は、nullアクセスなどプログラミングのミスによって発生する」

これらはJava SEの範囲に限定して言えば、ほぼ正しいです(反例は後述)。しかし、Java SEの範囲を超えるとそうとも限りません。

例えばSpring Frameworkで定義されている例外クラスは、ほぼすべてRuntimeExceptionのサブクラス、つまり非チェック例外です。データベースで発生するSQLExceptionやその他のチェック例外も、Spring独自の非チェック例外に変換するという徹底ぶりです。

一方、JSONを扱うJacksonというライブラリの例外はすべてIOExceptionのサブクラス、つまりチェック例外です。

Jackson 2ではすべてチェック例外でした。しかしJackson 3ではすべて非チェック例外になりました!(公式URL -> https://github.com/FasterXML/jackson-future-ideas/wiki/JSTEP-4

Jakarta EEの中でも、Jakarta Servletの例外はすべてチェック例外、Jakarta Persistence(旧JPA)の例外はすべて非チェック例外(JDBCのSQLExceptionがチェック例外であるにも関わらず)と、けっこう統一感がありません。

更に更にJava SEの中でも、チェック例外であるIOExceptionをラップする非チェック例外UncheckedIOExceptionがJava 8から導入されました。

こうなると、前出の基準は当てにならないですね。何となくですが、Jackson 3と言いUncheckedIOExceptionと言い、世の中の流れ的には非チェック例外が主流なっているのかなという感じはします。

例外を使わない例外処理もある

Java以外の言語だと、 Result とか Either とか呼ばれる、例外処理で利用する型が存在する場合があります(この記事では解説しませんので、詳細はAIさんやGoogleさんに聞いてみてください)。

JavaだとVavrというライブラリを使えば同じようなことができます。

結局どう使い分ければいいのか

結論から言うと「プロジェクト内で基準を決め、皆それに従いましょう」となります。

前述のとおり、世の中のフレームワーク/ライブラリでもそれぞれ異なります。これは、人によって思想がかなり異なることを示しています。

なので、プロジェクト内で皆で話し合って決めるしか無いと思います。

僕がリーダーをしているプロジェクトでは、Spring Frameworkが多いこともあり、すべて非チェック例外にしています。

実務をやりながら、どんなプロジェクトならどんな例外処理がいいのか考えてみてください。

Discussion

makingmaking

一方、JSONを扱うJacksonというライブラリで定義された例外は、すべてIOExceptionのサブクラス、つまりチェック例外です。

Jackson 3からはRuntimeExceptionになりました!🙌

1