Java Tips | コレクション:空List安全取得

Java Java
スポンサーリンク

空List安全取得は「null を“空”にそろえる」ための小さな約束

List を返すメソッドって、業務コードに山ほど出てきますよね。
検索結果、関連データ、設定値の一覧、などなど。

そこでよく起きるのが、このパターンです。

List<String> result = findNames();
if (result != null) {
    for (String name : result) {
        ...
    }
}
Java

毎回 result != null を書いていると、どこかで必ず書き忘れます。
そして、NullPointerException が飛ぶ。

空List安全取得は、ここを「そもそも null を返さない世界」に変えるためのユーティリティです。
「null かもしれない List」を、「必ず空か要素ありの List」に正規化するイメージです。


基本アイデア:null なら空Listに変換する

emptyIfNull という“正規化関数”を用意する

まずは、どんな List が来ても「null なら空Listにする」メソッドを用意します。

import java.util.Collections;
import java.util.List;

public final class ListUtils {

    private ListUtils() {}

    public static <T> List<T> emptyIfNull(List<T> list) {
        return (list == null) ? Collections.emptyList() : list;
    }
}
Java

使い方はとてもシンプルです。

List<String> names = null;

List<String> safe = ListUtils.emptyIfNull(names);
System.out.println(safe.size()); // 0
for (String n : safe) {          // nullチェック不要
    System.out.println(n);
}
Java

ここで重要なのは、次の2点です。

一つ目は、「呼び出し側が null を意識しなくてよくなる」ことです。
emptyIfNull を通した時点で、「この List は null ではない」と保証されるので、
for-each も list.size() も安心して呼べます。

二つ目は、「null と“要素がない”を同じ扱いにする」という設計を、
ユーティリティに閉じ込めていることです。
「該当なし=空List」というルールを徹底すると、
コード全体の分岐がかなり減ります。


呼び出し側のコードがどう変わるかを比べてみる

before:毎回 null チェックが必要な世界

従来の書き方だと、こうなりがちです。

List<String> names = findNames();

if (names != null && !names.isEmpty()) {
    for (String n : names) {
        ...
    }
}
Java

names != null を書き忘れると NPE。
isEmpty() を書き忘れると、無駄なループ。

after:空List安全取得を使った世界

空List安全取得を挟むと、こう書けます。

List<String> names = ListUtils.emptyIfNull(findNames());

for (String n : names) {
    ...
}
Java

「null かもしれない」という不安を、
emptyIfNull の中に押し込めてしまったイメージです。

ここで深掘りしたいポイントは、「null チェックの責任の場所を変えている」ということです。
今までは「呼び出し側が毎回責任を負っていた」のを、
「ユーティリティが一度だけ責任を負う」形に変えています。


戻り値側で「最初から空Listを返す」設計にする

そもそも null を返さないメソッドにする

もっと理想を言えば、
「List を返すメソッドは、null ではなく空Listを返す」
というルールにしてしまうのがベストです。

import java.util.Collections;
import java.util.List;

public class NameRepository {

    public List<String> findNames() {
        List<String> result = ...; // DBなどから取得
        if (result == null || result.isEmpty()) {
            return Collections.emptyList();
        }
        return result;
    }
}
Java

こうしておけば、呼び出し側は emptyIfNull すら要りません。

List<String> names = nameRepository.findNames();
for (String n : names) {
    ...
}
Java

ここでの重要ポイントは、「null を返すかどうかは“設計の約束事”」だということです。
「このプロジェクトでは、コレクションの戻り値に null は使わない」
と決めてしまえば、空List安全取得は「外部ライブラリや古いコードと接続するとき」だけに使えばよくなります。


Collections.emptyList() と new ArrayList<>() の違いも押さえておく

どちらも「空」だが、性質が違う

空Listを返すとき、よく使うのがこの2つです。

Collections.emptyList(); // 不変(変更不可)の空List
new ArrayList<>();       // 変更可能な空List
Java

空List安全取得では、基本的に Collections.emptyList() を使うのがおすすめです。

理由は二つあります。

一つ目は、「共有しても問題ないから」です。
Collections.emptyList() は中身が変わらないので、
どこに渡しても安全です。

二つ目は、「“ここでは追加しない前提”がはっきりするから」です。
emptyIfNull の戻り値に対して add しようとすると例外になるので、
「ここで追加するのは設計ミスだ」とすぐに気づけます。

List<String> safe = ListUtils.emptyIfNull(null);
safe.add("X"); // UnsupportedOperationException
Java

もし「呼び出し側で add したい」ケースなら、
emptyIfNull の後で明示的に new ArrayList<>(safe) すればよい、
という分離ができます。


実務での「空List安全取得」の使いどころ

外部ライブラリや古いコードとつなぐときの“防波堤”

外部ライブラリや、昔の自前コードは、
平気で「該当なしなら null を返す」メソッドを持っていたりします。

そういうメソッドを直接使うのではなく、
必ず空List安全取得を挟むようにすると、安全な境界線を引けます。

List<String> raw = legacyApi.getNames();          // null かもしれない
List<String> names = ListUtils.emptyIfNull(raw);  // ここから先は null ではない世界
Java

この「境界で正規化する」という考え方は、
業務システム全体の安定性を上げるうえで、とても大事な感覚です。


まとめ:空List安全取得で身につけてほしい感覚

空List安全取得は、単に「NPE を避ける小技」ではなく、
「null を“空”にそろえて、世界をシンプルにする」 ためのユーティリティです。

null なら Collections.emptyList() を返す emptyIfNull を用意する。
List を返すメソッドは、原則として null ではなく空Listを返す設計にする。
空Listには不変のもの(Collections.emptyList())を使い、「ここでは追加しない前提」を明確にする。
外部や古いコードとの境界で「null → 空List」に正規化し、内側の世界をシンプルに保つ。

もしあなたのコードのどこかに、

List<String> list = xxx();
if (list != null) {
    ...
}
Java

というパターンが何度も出てきているなら、
それを一度「空List安全取得+空Listを返す設計」に置き換えられないか、眺めてみてください。

その小さな整理が、
「null に振り回されない、安定したコレクション処理を書けるエンジニア」への、
確かな一歩になります。

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