Java | 基礎文法:NullPointerException

Java Java
スポンサーリンク

NullPointerException の全体像

NullPointerException(NPE)は「参照が null のまま、メソッド呼び出しやフィールド参照など“あるはずのもの”を使おうとした時」に発生する例外です。プリミティブ型(int、double、boolean など)は null になりませんが、参照型(String、配列、クラス、インターフェースなど)は null になり得ます。NPEは初心者が最初にぶつかる壁ですが、原因のパターンを知り、予防の作法を身につければ避けられます。


典型的な発生パターン

メソッド呼び出し・フィールド参照の前提違反

String s = null;
int len = s.length(); // NPE(参照が null)
Java

参照が null のままメソッドを呼ぶと必ずNPEになります。まず「その参照は本当に non-null か?」を疑い、使用前にガード(nullチェック)を入れます。

配列・コレクションの参照

String[] a = null;
int n = a.length; // NPE(配列参照が null)

java.util.List<String> list = null;
list.add("x"); // NPE(リスト参照が null)
Java

「要素が null」と「参照が null」は別物です。参照自体が null だと、どんな操作もNPEになります。

オートアンボクシング(ラッパー → プリミティブ)

Integer x = null;
// int v = x; // NPE(アンボクシング時に発生)
Java

ラッパー型(Integer, Boolean など)をプリミティブへ自動変換する「アンボクシング」は、元が null だとNPEになります。null ガード、既定値への置き換え、Optional の活用で防ぎます。

equals の呼び出し順

String s = null;
// s.equals("OK"); // NPE(左が null)
"OK".equals(s);          // 安全(左は非 null)
java.util.Objects.equals(s, "OK"); // どちらかが null でも安全
Java

左オペランドが null になり得る比較は、非 null 側から呼ぶか、Objects.equals を使うと安全です。


予防の基本作法(重要ポイントの深掘り)

短絡評価で「安全確認 → 使用」の順を守る

String s = null;
if (s != null && s.length() > 0) {
    // 右は安全に評価される
}
Java

&& は左が false なら右を評価しません(短絡)。先に null チェック、次に利用という順序を徹底します。

入力検証を入口で終わらせる(早期ガード)

import java.util.Objects;

static String upper(String s) {
    Objects.requireNonNull(s, "s must not be null");
    return s.toUpperCase();
}
Java

契約として「null を許さない」なら、入口で早期に弾いて曖昧さを消します。許す設計なら、既定値へ正規化します。

static String safeUpper(String s) {
    if (s == null) return "";
    return s.toUpperCase();
}
Java

Boolean は常に null セーフに扱う

Boolean flag = null;
if (Boolean.TRUE.equals(flag)) {
    // true の時だけ入る。null は false と同等扱い
}
Java

アンボクシングを避け、Boolean.TRUE/Boolean.FALSE.equals(...) を用いると安全です。

Optional で「有無」を型にする

import java.util.Optional;

static Optional<String> find(String[] arr, String key) {
    for (String s : arr) if (java.util.Objects.equals(s, key)) return Optional.of(s);
    return Optional.empty();
}

// 呼び出し側
String val = find(new String[]{"A","B"}, "C").orElse("not found");
Java

戻り値を Optional にすると、「無い」ことを null ではなく型で表せます。呼び出し側は orElse/orElseGet/ifPresent で安全に扱えます。


Map/コレクションの null と設計の落とし穴

Map.get の戻り値は null になり得る

java.util.Map<String, String> m = new java.util.HashMap<>();
String v = m.get("key"); // キーが無ければ null
Java

「値が null」なのか「キーが無い」のかが曖昧です。必要なら containsKey と組み合わせて判断を分けます。可能なら「値に null を使わない」方針にして、空文字や Optional に統一します。

コレクションに null を入れない

リストやセットに null を許容すると、操作のたびに null ガードが必要になり、バグの温床になります。できる限り「空コレクションで表現」する設計にします。

java.util.List<String> xs = java.util.List.of(); // なし=空
Java

NPE のデバッグ:スタックトレースを読む

どこで null を使ったかを特定する

スタックトレースの先頭行(原因行)に「クラス名.メソッド名(ファイル名:行番号)」が出ます。まずその行を開き、どの参照が null かを特定します。次に、その参照が「どこで設定されるはずだったか」「どの分岐で設定漏れが起きたか」を遡ります。

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "s" is null
    at Sample.main(Sample.java:5)

最近のJDKではメッセージに「どの変数が null だったか」も表示されます。原因特定が速くなるため、JDKの更新も有効な防御策です。


実例で身につける

例 1: null セーフな比較と分岐

public class NullCompare {
    static boolean isOk(String s) {
        return java.util.Objects.equals(s, "OK");
    }
    public static void main(String[] args) {
        System.out.println(isOk(null));  // false
        System.out.println(isOk("OK"));  // true
    }
}
Java

例 2: オートアンボクシングを避けて安全に扱う

public class SafeBoolean {
    static boolean isEnabled(Boolean b) {
        return Boolean.TRUE.equals(b); // null でも安全
    }
    public static void main(String[] args) {
        System.out.println(isEnabled(null));          // false
        System.out.println(isEnabled(Boolean.FALSE)); // false
        System.out.println(isEnabled(Boolean.TRUE));  // true
    }
}
Java

例 3: Optional と短絡評価でNPEを防ぐ

import java.util.*;

public class Normalize {
    static Optional<String> normalize(String s) {
        if (s == null || s.isBlank()) return Optional.empty();
        return Optional.of(s.trim());
    }
    public static void main(String[] args) {
        String safe = normalize(null).orElse("N/A");
        System.out.println(safe); // "N/A"
    }
}
Java

仕上げのアドバイス(重要部分のまとめ)

NPE は「null を“あるはずのもの”として使った瞬間」に出ます。使用前に null ガード、短絡評価の順序、equals の呼び順を徹底する。アンボクシングのNPEは Boolean.TRUE.equals(...) などの null セーフ作法で防ぐ。戻り値の「有無」は Optional で型にし、コレクションに null を入れない。契約として null を禁止する場面では Objects.requireNonNull で早期に弾く。詰まったらスタックトレースを一行目から読み、どの参照が null だったかを特定して、設定漏れの分岐を直す——この癖がつけば、NPEは“たまに来ても一瞬で直す”相手になります。

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