JavaのSpringの@ExceptionHandlerアノテーションを完全ガイド!初心者でもわかる例外処理
生徒
「Springでエラーが発生したときに、どうやって適切な処理を行えばいいですか?」
先生
「Springでは、@ExceptionHandlerアノテーションを使って例外をキャッチし、適切に処理できます。」
生徒
「それって、どういう風に設定すればいいんですか?」
先生
「具体的な例を見ながら、基本の使い方を一緒に学びましょう!」
1. @ExceptionHandlerアノテーションとは?
Springの@ExceptionHandlerアノテーションは、アプリケーション内で例外(エラー)が発生したときに、その例外専用の処理を行うための仕組みです。Javaでは、エラーが起きるとプログラムが途中で止まってしまうことがありますが、Springではこのアノテーションを使うことで、エラー発生時でも安全に処理を続けることができます。
特にWebアプリケーションでは、「画面が真っ白になる」「何が起きたかわからない」といった状態を防ぐことが重要です。@ExceptionHandlerを使えば、エラー内容に応じてメッセージを表示したり、適切なHTTPレスポンスを返したりできるため、ユーザーにも開発者にもやさしい設計になります。
まずは、プログラミング未経験者でもイメージしやすい、シンプルな例を見てみましょう。
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@ExceptionHandler(ArithmeticException.class)
public String handleArithmeticException(ArithmeticException e) {
return "計算中にエラーが発生しました。数値を確認してください。";
}
}
この例では、「0で割り算をした」などの計算エラー(ArithmeticException)が発生した場合に、このメソッドが自動的に呼び出されます。難しい設定は不要で、「この例外が起きたら、このメッセージを返す」と直感的に書けるのが特徴です。
このように@ExceptionHandlerは、エラー処理をわかりやすく整理し、アプリ全体の安定性を高めるための重要なアノテーションとして、Spring開発では欠かせない存在です。
2. 基本的な@ExceptionHandlerの使い方
@ExceptionHandlerの基本的な使い方はとてもシンプルで、「どの例外が発生したときに、どの処理を行うか」をメソッド単位で定義します。JavaやSpringを初めて触る方でも、例外の種類と処理内容をセットで書けるため、エラー対応の流れを理解しやすいのが特徴です。
まずは、アプリ全体で発生するエラーをまとめて処理する、一般的な例を見てみましょう。ここでは@ControllerAdviceを使い、どの画面でも共通して動作する例外処理を定義しています。
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<String> handleNullPointerException(NullPointerException ex) {
return new ResponseEntity<>("NullPointerException has occurred: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleGenericException(Exception ex) {
return "An error occurred: " + ex.getMessage();
}
}
このサンプルでは、よく発生しやすいNullPointerExceptionと、それ以外のすべての例外を分けて処理しています。たとえば、プログラム内で値が入っていない変数を使ってしまった場合、Springは自動的に対応する@ExceptionHandlerメソッドを呼び出します。
また、ResponseEntityや@ResponseStatusを使うことで、エラー時に返すHTTPステータスを明確に指定できます。これにより、ブラウザやAPIの利用者が「どんなエラーが起きたのか」を正しく判断できるようになります。
このように、@ExceptionHandlerの基本を押さえることで、エラーが起きても落ち着いて対応できる、安定したSpringアプリケーションを作ることができます。
3. @ControllerAdviceを使ったグローバル例外処理
@ControllerAdviceは、アプリケーション全体で共通して使う例外処理をまとめて定義できる仕組みです。通常、例外処理を各コントローラーに書いてしまうと、同じようなコードが何度も登場し、修正や管理が大変になります。
@ControllerAdviceを使うことで、「どの画面・どのAPIでエラーが起きても、このルールで処理する」という共通ルールを作ることができます。これは、WebアプリケーションやREST APIを作るうえで、非常に重要な考え方です。
プログラミング未経験の方は、「学校全体に適用される校則」のようなものだと考えるとイメージしやすいでしょう。個々のクラス(コントローラー)に書かなくても、全体に同じ決まりを適用できます。
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public String handleRuntimeException(RuntimeException e) {
return "予期しないエラーが発生しました。しばらくしてから再度お試しください。";
}
}
このサンプルでは、アプリ内で発生したRuntimeExceptionをすべてまとめて処理しています。どのコントローラーでエラーが起きても、このメソッドが呼び出され、同じメッセージが返されます。
このように@ControllerAdviceを使えば、例外処理の記述を一か所に集約でき、コードが読みやすくなります。また、エラーメッセージの内容を統一できるため、ユーザーにとってもわかりやすいアプリケーションになります。
4. 実行結果
それでは、実際に例外が発生した場合、どのような結果が返ってくるのかを見てみましょう。ここでは、NullPointerExceptionが発生したケースを想定しています。
ブラウザやAPIクライアントからリクエストを送信し、処理中にエラーが起きると、Springは自動的に対応する@ExceptionHandlerメソッドを呼び出します。その結果、次のようなレスポンスが返されます。
NullPointerException has occurred: null
このメッセージは、例外処理クラス内で定義した戻り値がそのまま表示されたものです。プログラムが途中で止まることなく、エラー内容をわかりやすい形で返せている点が重要です。
プログラミング未経験の方でも、「エラーが起きたら、このメッセージが表示される」と把握できれば十分です。@ExceptionHandlerを使うことで、利用者にとっても開発者にとっても状況を理解しやすい実行結果を用意できるようになります。
5. よくある質問と解決方法
Q: @ExceptionHandlerが動作しない場合は?
A: @ControllerAdviceクラスがSpringのコンポーネントスキャンで認識されているか確認してください。
Q: 例外ごとに異なるエラーページを表示するには?
A: ModelAndViewを返す@ExceptionHandlerメソッドを定義します。
6. @ExceptionHandlerで複数の例外をまとめて処理する方法
@ExceptionHandlerは、1つのメソッドで複数の例外クラスをまとめて処理することも可能です。似たようなエラー処理を個別に書く必要がなくなり、コードをすっきり保つことができます。
たとえば、入力チェックに関連する例外をまとめて扱いたい場合に便利です。例外ごとに細かく分けすぎず、役割ごとに整理すると保守性が向上します。
7. @ExceptionHandlerとHTTPステータスの関係
@ExceptionHandlerでは、例外発生時に返すHTTPステータスコードを明示的に指定できます。ResponseEntityを使う方法や、@ResponseStatusアノテーションを使う方法があります。
これにより、クライアント側はエラーの種類をHTTPステータスから判断できるようになります。REST APIを作成する場合は、適切なステータスコードを返すことが非常に重要です。
8. @ExceptionHandlerを使う際の設計ポイント
@ExceptionHandlerを使う際は、例外処理の責務を明確に分けることが大切です。コントローラー内で処理する例外と、@ControllerAdviceで一括処理する例外を整理しましょう。
アプリケーション全体に影響する例外はグローバル例外ハンドラーで管理し、特定の画面や機能に依存する例外のみ個別に処理することで、読みやすく拡張しやすい構成になります。
まとめ
本記事では、Springフレームワークにおける例外処理の重要性と、@ExceptionHandlerアノテーションの基本的な使い方を学びました。
@ControllerAdviceと組み合わせることで、アプリケーション全体で統一的な例外処理を実現できることも理解しました。
以下に、本記事の内容を振り返りながら、実際のプロジェクトにどのように適用できるかを整理します。
@ExceptionHandlerのポイント
- 局所的な例外処理: 各コントローラークラスで特定の例外を処理する。
- グローバル例外処理:
@ControllerAdviceを利用してアプリケーション全体で一貫性のある処理を定義。 - 柔軟なレスポンス構成:
ResponseEntityやステータスコードを利用してクライアントに適切なレスポンスを返す。
具体例: 新たな例外を追加
以下は、IllegalArgumentExceptionを処理する例です。
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
return new ResponseEntity<>("Invalid argument: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
}
このようにして、アプリケーションの要件に応じた例外処理を柔軟に追加できます。
生徒
「今日学んだ@ExceptionHandlerを使えば、エラーが起きたときにアプリが止まるのを防げそうですね!」
先生
「その通りです。特に、@ControllerAdviceと組み合わせれば、全体的な例外処理を簡潔に管理できます。」
生徒
「他の例外も処理したいときはどうすればいいですか?」
先生
「新しい例外を追加するには、対応する@ExceptionHandlerメソッドを定義するだけで簡単に実現できます。」
生徒
「それなら、クライアントに返すエラーメッセージもカスタマイズできますね!」
先生
「そうですね。レスポンス内容やHTTPステータスコードを状況に応じて設定してください。」