Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】A Beginner’s Guide to Exception Handling in Java

2025年09月21日に「Dev.to」が公開したITニュース「A Beginner’s Guide to Exception Handling in Java」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Javaの例外処理ガイド。初心者がNullPointerExceptionに直面し、ログで原因を特定。Spring Bootの`@ControllerAdvice`を用いた集中例外処理を学び、システムエラーを分かりやすいAPI応答に改善した経験を紹介する。例外はデバッグの指針であり、適切な処理でAPIの信頼性が向上する。

ITニュース解説

システムエンジニアを目指す皆さんにとって、プログラミング学習の中で避けて通れないのが「エラー」との遭遇です。特にJavaを使ったバックエンド開発では、「例外(Exception)」という形でさまざまな問題に直面することがあります。今回は、ある開発者が実際に経験したNullPointerExceptionという代表的な例外との格闘を通じて、Javaにおける例外処理の考え方、デバッグの進め方、そしてより堅牢なシステムを構築するための実践的なアプローチを解説します。

多くの初心者がそうであるように、この開発者も最初は例外を「プログラムを止めてしまう恐ろしい赤いエラー」だと捉えていました。しかし、実際にJavaとSpring Bootというフレームワークを使ってユーザーの詳細情報を返すAPIを開発した際、予期せぬNullPointerExceptionが発生し、その認識はすぐに打ち砕かれます。APIは「500 Internal Server Error」というエラーを返し、大量のログがコンソールに流れ、開発者はどこから手をつければ良いか途方に暮れました。これは、誰もが経験する典型的な「壁」と言えるでしょう。

問題の兆候は、ユーザー情報を取得する /users/{id} というAPIエンドポイントにリクエストを送ったときに現れました。期待していたユーザー情報のJSONデータではなく、以下のようなエラーメッセージが表示されたのです。

java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null at com.example.demo.service.UserService.getUser(UserService.java:25) at com.example.demo.controller.UserController.getUser(UserController.java:18)

このメッセージは、プログラムが「name」という変数に対して「length()」という操作を行おうとしたが、「name」が「null」(何も参照していない状態)であったために処理を続行できなかった、と告げています。さらに、エラーが発生したのが UserService.java の25行目、そしてその呼び出し元が UserController.java の18行目であることも示されています。これは「スタックトレース」と呼ばれる情報で、エラーがどこで発生し、どのような経路を辿ってそこに至ったかを示してくれます。この時点で、プログラムは沈黙するのではなく、大きな声で「ここに問題がある!」と叫んでいたことに気づかされます。

次に、この問題を具体的に特定するためのデバッグが始まりました。デバッグとは、プログラムの誤り(バグ)を見つけ出し、修正する作業のことです。開発者は UserService クラスの getUser メソッドに、System.out.println("DEBUG: Input name is -> " + name); という一行のコードを追加しました。これは、プログラムの実行中に特定の変数の値を確認するための、最もシンプルながら強力なデバッグ手法の一つです。再度APIにリクエストを送ると、コンソールには DEBUG: Input name is -> null という出力が表示されました。この瞬間、問題が toUpperCase() のような文字列操作の処理自体にあるのではなく、そもそも getUser メソッドに渡される「name」という入力パラメータが null であることが明らかになりました。つまり、APIに正しいデータが渡されていなかった、あるいは取得できていなかったことが原因だったのです。

この発見を経て、開発者は単にエラーが出た箇所を個別に try-catch ブロックで囲むような場当たり的な対応ではなく、より体系的で「バックエンドらしい」解決策を模索し始めました。バックエンド開発における「ベストプラクティス」(最も良いとされる手法)を求めて、「Spring Boot exception handling best practices」というキーワードでインターネット検索を行った結果、Springの公式ドキュメントにたどり着きます。

そこで得られた知識は、例外処理の理解を深める上で非常に重要でした。Javaには大きく分けて二種類の例外があることを学びました。一つは「チェック済み例外(Checked Exception)」と呼ばれるもので、これらはファイル入出力など、プログラムの外部要因によって発生する可能性があり、開発者はコード上で必ずその例外を処理するか、あるいはさらに上位のメソッドに処理を委ねる(スローする)ことを宣言しなければなりません。もう一つは、今回直面したNullPointerExceptionのような「非チェック例外(Unchecked Exception)」または「実行時例外(RuntimeException)」です。これらはプログラムのロジックの誤りなどによって実行時に発生し、通常は明示的に try-catch で囲む必要はありませんが、発生するとプログラムがクラッシュします。Spring Bootのようなフレームワークでは、このような実行時例外を含め、発生する可能性のあるエラーを一箇所でまとめて処理する「集中型エラーハンドリング」が推奨されており、そのための強力な仕組みとして @ControllerAdvice というアノテーションが紹介されていました。

この知識を元に、開発者は具体的な解決策の実装に取り掛かりました。@RestControllerAdvice アノテーションを付与した GlobalExceptionHandler というクラスを作成し、その中に @ExceptionHandler アノテーションを使って特定の例外を処理するメソッドを定義しました。

まず、@ExceptionHandler(NullPointerException.class) を指定した handleNullPointer メソッドで、NullPointerExceptionが発生した場合の処理を記述しました。このメソッドは、クライアントに対して「Oops! A required value was missing.」(おっと、必要な値がありませんでした)というメッセージと共に、HTTPステータスコードとして HttpStatus.BAD_REQUEST(400番台、クライアントからのリクエストに問題があることを示す)を返すようにしました。これにより、APIの利用者は何が問題だったのかを具体的に理解できるようになります。

さらに、@ExceptionHandler(Exception.class) を指定した handleGeneralException メソッドも追加しました。これは、NullPointerException以外の、あらゆる種類の一般的な例外を捕捉するためのものです。このメソッドは、「Something went wrong: [エラーメッセージ]」という汎用的なメッセージと HttpStatus.INTERNAL_SERVER_ERROR(500番台、サーバー側で予期せぬエラーが発生したことを示す)を返すように設定しました。この二つのハンドラを組み合わせることで、API全体で発生する可能性のあるほとんどの例外を統一的に処理できるようになります。

この変更を適用した結果、以前は生のスタックトレースという、プログラミングに詳しくない人には理解しがたいエラーメッセージが返されていたAPIが、今では「{ "error": "Oops! A required value was missing." }」という、利用者にとって非常に分かりやすく、親切なレスポンスを返すようになりました。これにより、APIを使うクライアントアプリケーションは、サーバーから返されたエラーの内容を基に適切な処理を行うことができるようになり、開発者もエラーの原因を特定しやすくなります。

この一連のデバッグと解決策の実装を通じて、開発者はいくつかの重要な教訓を得ました。一つ目は、例外は単にプログラムを止める厄介なエラーではなく、問題の場所と種類を教えてくれる「デバッグのガイド」であるということです。二つ目は、バックエンド開発におけるデバッグの第一歩として、ログ(System.out.println やより専門的なロギングライブラリ)を活用して変数の値やプログラムの実行状態を確認することが非常に有効であるという点です。三つ目は、@ControllerAdvice を用いた集中型例外ハンドリングが、APIをより堅牢で使いやすいものにするための重要なベストプラクティスであるということです。そして最後に、API利用者に対して意味のある、人間が読めるエラーメッセージを返すことが、開発者とAPI利用者双方にとって、円滑なコミュニケーションと問題解決を促進するという結論に至りました。

システムエンジニアを目指す皆さんにとって、エラーは避けられない存在ですが、それを単なる障害と捉えるのではなく、成長のための貴重な学びの機会と捉えることが大切です。今回の経験談が、皆さんが将来、複雑なシステム開発の中で直面するであろう問題に対処するための、確かな一歩となることを願っています。