NullPointerException を “やさしく深く” 理解する【初心者向け+内部構造の解説】

🍀 【初心者向け】NullPointerException(NPE)はなぜ起きる?

Java を学び始めた人が 100%つまずくエラー
NullPointerException(以下 NPE)です。

Exception in thread "main" java.lang.NullPointerException

突然これが出てきて、
「え? どこが null なの?」
と混乱することは誰もが経験します。

まずは、NPE の正体 を一言でまとめます👇


✔ 結論:参照先が “空(null)” のまま使われたときに出るエラー

Java は
「オブジェクトの実体(中身)」を ヒープ領域に作り
「その場所」を 参照(アドレス)で指し示す
という動作をしています。

つまり:

  • オブジェクト → ヒープ
  • 参照(変数) → スタック

この “参照” に アドレスが入っていない状態(null)
メソッドを呼ぶと NPE が発生します。

図で表すとこう👇

String s;     // 参照だけ作られる(中身なし)
s.length();   // ← 中身がない状態で使ったので NPE!

🧪 【例①】一番シンプルな NPE

String name = null;
int length = name.length(); // NPE!

name に “中身(オブジェクト実体)” が存在しません。
なのに length() を呼んだから NPE が出ます。


🧩 【例②】初心者がよくハマる NPE の典型パターン

🔸 パターンA:フィールドだけ宣言して初期化を忘れている

public class UserService {
    private UserRepository repo; // ★ 初期化されていない null

    public void load() {
        repo.findAll(); // ★ repo が null なので NPE
    }
}

初心者あるあるです。


🔸 パターンB:配列やリストの中身が null

User[] users = new User[3]; // 長さ3だが中身は全部 null
users[0].getName(); // NPE

🔸 パターンC:Optional の扱い方を間違える

Optional<User> user = Optional.ofNullable(null);
user.get();  // NPEではないが NoSuchElementException

🌟 【ここから大事】

NPE は “スタックとヒープの関係” を知ると一気に理解できる

Java の内部では、「参照」と「実体」が完全に分かれています。


🧠 JVM 内部構造(やさしく)

■ スタック(stack)

  • メソッド内のローカル変数
  • 参照(アドレスの入った箱)

が置かれる場所。

■ ヒープ(heap)

  • new されたオブジェクトの “実体” が存在
  • こちらには名前はない
  • スタック変数がアドレスを指しているだけ

🔍 NPE が起きる内部動作イメージ

String s = null; // s は「何も指していない」
s.length();      // JVM「中身がないのに 呼ぼうとしてるやん!」→ NPE

より正確には JVM はこう考えています👇

  1. s.length() を実行しようとする
  2. s が指すアドレスを辿ろうとする
  3. しかしアドレスが「0番地(null)」
  4. 0番地の中身を読めないため例外

NullPointerException


🛡 NPE の防ぎ方(シンプル版)

✔ ① null を許容しない設計にする

String name = ""; // 空文字で初期化
List<User> users = new ArrayList<>();

✔ ② 早めに null チェックする

if (user == null) return;

✔ ③ Optional を正しく使う

Optional.ofNullable(user)
        .ifPresent(u -> System.out.println(u.getName()));

✔ ④ コンストラクタで必ず初期化する

public class Service {
    private final Repository repo;

    public Service(Repository repo) {
        this.repo = repo; // 必ず入る
    }
}

🌌 【ニッチ編】NPE が「起きる場所」と「起きる行」がズレる現象

実は Java のコンパイル最適化により、

NPE の原因となる参照と、
実際にエラーが出る行が一致しないことがある

という現象が起きます。

例👇

user.getAddress().getCity().getName();

どの部分が null か分かりにくい。
これを “NPE チェーン問題” と呼びます。

本当はこう分解されます👇

user → null?
address → null?
city → null?
name → null?

🌠 これを防ぐには?

  • 変数を分けて書く
  • デバッガを使う
  • Optional を分解して使う
  • チェーン記法を避ける

📝 まとめ

  • NPE は「null の参照を使った」時に必ず起きる
  • スタックとヒープの関係を理解すると一気に納得できる
  • 初期化忘れが最も多い原因
  • チェーン呼び出しは危険
  • Optional や初期化で安全にできる

コメント

タイトルとURLをコピーしました