Java | 基礎文法:null

Java Java
スポンサーリンク

null の全体像

null は「参照がどのオブジェクトも指していない」ことを表す特別な値です。プリミティブ型(int、double、boolean など)には存在せず、参照型(String、配列、クラス、インターフェースなど)でのみ使われます。変数・フィールド・配列要素が未初期化のままでも、参照型なら既定値は null になります。便利な反面、操作を誤ると NullPointerException(NPE)の温床になります。


基本動作とデフォルト値

デフォルト初期化の挙動

class Box {
    String name;        // 既定で null
    int count;          // 既定で 0
}
Java

参照型のフィールドや配列要素は、初期化を省略すると null です。ローカル変数はデフォルト初期化されないため、使う前に必ず代入してください(未初期化のまま使うとコンパイルエラー)。

null 参照に対する操作

String s = null;
// s.length();          // NPE(メソッド呼び出しは不可)
boolean eq = (s == null);   // 比較は可能
Java

「参照が無い」ため、メソッド呼び出し・フィールドアクセスはできません。使用前に null ガードを入れるのが基本です。


NullPointerException の典型と対策(重要ポイントの深掘り)

典型パターン

String s = null;
if (s.equals("OK")) { /* ... */ }     // NPE(左が null)
Java

対策は「null の可能性がある側を右に置く」またはユーティリティを使います。

if ("OK".equals(s)) { /* ... */ }     // 安全(左は非 null)
if (java.util.Objects.equals(s, "OK")) { /* ... */ } // どちらかが null でも安全
Java

コレクション操作でも起きがちです。

java.util.Map<String, String> m = new java.util.HashMap<>();
String v = m.get("key");  // 見つからなければ null(キーが無いのか、値が null なのか判別不能)
Java

必要なら「キー有無の判定」と「値の null」を分けて扱います。

if (m.containsKey("key")) {
    String v2 = m.get("key"); // 値が null かどうかは別途判断
}
Java

早期検証と防御的プログラミング

API 入口で null を許可しないなら、早期に検証して失敗を明示化します。

import java.util.Objects;

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

許可するなら「既定値で置き換える」設計にします。

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

null の比較と安全な等価判定

== と equals の使い分け

== は「参照が同じか」を比較します。値の比較は equals を使いますが、左オペランドが null だと NPE になります。次のどれかに統一すると安全です。

"OK".equals(s)                         // 左を非 null に固定
java.util.Objects.equals(s, "OK")      // どちらも null セーフ
Java

並び替えや検索での null セーフ

並び替えは Comparator の nullsFirst/nullsLast を使うと安全です。

var list = new java.util.ArrayList<>(java.util.List.of("b", null, "a"));
list.sort(java.util.Comparator.nullsLast(String::compareTo));
Java

API 設計の方針:許容・禁止・Optional(重要ポイントの深掘り)

「null を許すか」を最初に決める

  • 禁止するなら、入口で requireNonNull。ドキュメントにも「null不可」を明記。
  • 許可するなら、戻り値や副作用の契約を具体的に書く(例:nullの場合は空文字を返す)。

Optional で「有無」を型表現する

null を返す代わりに Optional<T> で結果の有無を示すと、呼び出し側が安全に扱えます(ライブラリ的コードに特に有効)。

import java.util.Optional;

static Optional<String> findStartsWith(String[] arr, String prefix) {
    for (String s : arr) if (s.startsWith(prefix)) return Optional.of(s);
    return Optional.empty();
}

// 呼び出し側
String v = findStartsWith(new String[]{"java","js"}, "ja").orElse("なし");
Java

注意点として、Optional は「戻り値」に向いています。フィールドや引数に使うのは過剰になりがちです(呼び出しが煩雑になるため)。


コレクション・ストリームと null の扱い

コレクションに null を入れる是非

リストやマップの値として null を許すと、バグの温床になります。可能なら「空のコレクション」「Optional」「既定値」で置き換え、null を避ける方針にします。

java.util.List<String> xs = java.util.List.of(); // 「なし」を空リストで表現
Java

ストリームでの null フィルタ

ストリームは null を要素に含めないのが基本です。混入し得るなら最初にフィルタで除去します。

var list = java.util.Arrays.asList("a", null, "b");
var cleaned = list.stream().filter(java.util.Objects::nonNull).toList();
Java

実例で身につける

例 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: Optional を使った探索

import java.util.*;

public class FindOpt {
    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();
    }
    public static void main(String[] args) {
        var r = find(new String[]{"A","B"}, "C").orElse("not found");
        System.out.println(r);
    }
}
Java

例 3: 入口で方針を固定(禁止と既定値)

public class Policy {
    static String mustNonNull(String s) {
        java.util.Objects.requireNonNull(s, "s must not be null");
        return s.trim();
    }
    static String allowNull(String s) {
        return (s == null) ? "" : s.trim();
    }
}
Java

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

null は「参照がない」ことを示すだけで、操作はできません。NPEの典型を避けるために、equals の呼び出し順や Objects.equals を習慣化し、API入口で「許容か禁止か」を決めて一貫させる。返り値の「有無」は Optional が有効で、コレクションには極力 null を入れない。マップの null は「キー無し」との区別が曖昧になるため、方針を決めて運用する。迷ったら「早期ガード」「既定値」「Optional」の3手で、nullを“仕様として”扱い、偶発的なエラー源にしないことが大切です。

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