01 / BASIC
そもそも null とは何なのか
Javaでは、 変数に値が入っているとは限りません。
オブジェクト型の変数には、 「どのオブジェクトも参照していない」 状態があります。
String name = null;
この状態では、
name は文字列オブジェクトを
参照していません。
nullは「空文字」でも「0」でもありません。 「参照するオブジェクトが存在しない」 という状態です。
02 / ERROR
なぜ NullPointerException が起きるのか
問題になるのは、 nullの状態の変数に対して メソッドを呼び出した場合です。
String name = null;
System.out.println(
name.length()
);
name は
どのStringオブジェクトも
参照していません。
その状態で
name.length()
を実行しようとするため、
Javaは処理対象となるオブジェクトを
見つけられません。
Exception in thread "main"
java.lang.NullPointerException
03 / IMAGE
nullをイメージすると分かりやすい
例えば、
String name = null;
という状態を、 「住所だけあって家が存在しない」 と考えてみます。
「nameという変数は存在する」
けれど、
「nameが参照しているオブジェクトは存在しない」
という状態です。
04 / PRACTICAL
業務システムではどこで起きるのか
実際の業務システムでは、 nullを直接書いているケースよりも、 「処理の途中でnullになっていた」 というケースの方が多くあります。
User user = findUser(id);
String name = user.getName();
一見すると問題なさそうですが、
findUser(id) が
ユーザーを見つけられなかった場合、
user がnullになる可能性があります。
User user = findUser(id);
if (user != null) {
String name = user.getName();
}
このように、 オブジェクトが存在することを確認してから メソッドを呼び出します。
NullPointerExceptionの原因を探すときは、 エラーになった行だけを見るのではなく、 「その変数にどこから値が入ってきたのか」 を追うことが重要です。
05 / DEBUG
エラーが出たら何を見るか
NullPointerExceptionが発生した場合、 まず見るのはスタックトレースです。
java.lang.NullPointerException
at UserService.getUserName(UserService.java:25)
at Main.main(Main.java:10)
ここで重要なのは、
UserService.java の25行目
という情報です。
ただし、 25行目だけを修正すれば終わりとは限りません。
例えば、
User user = userRepository.findById(id);
return user.getName();
というコードなら、
問題は getName() ではなく、
その前の
findById(id)
がnullを返していることかもしれません。
06 / THINKING
「nullチェック」だけでは終わらない
初心者の頃は、 NullPointerExceptionを見ると とりあえずnullチェックを追加したくなります。
if (user != null) {
// 処理
}
もちろん必要な場合もあります。
ただし、 本当に重要なのは、
「なぜuserがnullになる可能性があるのか?」
を考えることです。
DBにデータがないのか。 APIのレスポンスに含まれていないのか。 条件分岐を通っていないのか。 初期化されていないのか。
原因によって、 本来取るべき対応は変わります。
FIELD NOTE
エラーが起きた場所と、
原因は同じとは限らない。
NullPointerExceptionで 「この行が悪い」と思って修正したら、 別の場所で同じエラーが出る。
こういうことは、 業務システムでは珍しくありません。
重要なのは、
nullになった瞬間を探すこと。
そのためには、
メソッドの呼び出し元、
DBの検索結果、
APIレスポンスなど、
データの流れを追っていく必要があります。
SUMMARY
NullPointerExceptionを理解する
NullPointerExceptionは、 単純に「nullだから起きるエラー」 と覚えるだけでは少しもったいありません。
大切なのは、
という状態になっていないかを見ることです。
そして実際の開発では、 「どこでnullになったのか」を追うことが エラー解決の第一歩になります。