Java Tips | コレクション:Map初期化

Java Java
スポンサーリンク

Map初期化は「キーと値の世界の“ルール決め”」から始まる

Mapの初期化は、単に「空のMapを作る」「最初からいくつかのキーと値を入れておく」だけの話に見えますが、
その瞬間に「変更できるか」「順序を保つか」「nullを許すか」といった性質が決まります。

業務コードでよくあるトラブルは、
「あとでputしたいのに、変更不可のMapを作ってしまった」
「nullを返してしまって、呼び出し側が毎回nullチェックしている」
といった“初期化の設計ミス”です。

だからこそ、「このMapは何に使うのか」を意識して、
用途に合った初期化パターンを身につけておくことが大事です。


一番基本:可変の空Mapを作る(new HashMap<>())

「あとでputしていく前提」の標準形

業務で一番よく使うのは、「最初は空だけど、あとでキーと値を追加していくMap」です。
この場合は、素直に new HashMap<>() を使うのが基本です。

import java.util.HashMap;
import java.util.Map;

public class MapInitBasic {

    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();

        scores.put("山田", 80);
        scores.put("佐藤", 90);

        System.out.println(scores); // {山田=80, 佐藤=90}
    }
}
Java

ここで押さえておきたい重要ポイントは二つです。

一つ目は、「変更可能なMap(可変Map)を作っている」ということです。
putremove が自由にできるので、「あとから増える・減る」前提のデータに向いています。

二つ目は、「変数の型は Map、実体は HashMap」という書き方にしていることです。
Map<String, Integer> scores = new HashMap<>(); のように、
インターフェース型(Map)で受けておくと、
あとで実装を LinkedHashMapTreeMap に変えたくなったときも、
呼び出し側のコードをほとんど変えずに済みます。


「最初から中身が決まっているMap」を作る

Map.of で不変の小さなMapを手軽に作る

「最初からキーと値が決まっていて、すぐに使いたい」という場面も多いです。
例えば、固定のコード→ラベルの対応表や、テストデータなどです。

Java 9以降なら、Map.of を使うと簡潔に書けます。

import java.util.Map;

public class MapInitFixed {

    public static void main(String[] args) {
        Map<String, String> labels = Map.of(
                "NEW", "新規",
                "IN_PROGRESS", "処理中",
                "DONE", "完了"
        );

        System.out.println(labels.get("NEW")); // 新規
    }
}
Java

ここでの重要ポイントは、「このMapは完全に不変(変更不可)」ということです。

labels.put("CANCEL", "キャンセル");   // UnsupportedOperationException
labels.remove("NEW");                 // UnsupportedOperationException
Java

業務で「定数的なマスタ」「絶対に変わってほしくない対応表」を扱うときは、
Map.of で不変Mapにしておくと安心です。
どこかのコードがうっかり put しても例外になり、
「いつの間にかマスタが書き換わっていた」という事故を防げます。


「可変Mapが欲しいけど、初期値も入れたい」場合の定番パターン

不変Mapを元にして、可変Mapを作る

よくあるのが、
「最初からいくつかのキーと値を入れておきたいが、その後もput/removeしたい」
というパターンです。

この場合は、「不変Mapを元にして、可変Mapを作る」という書き方が定番です。

import java.util.HashMap;
import java.util.Map;

public class MapInitMutable {

    public static void main(String[] args) {
        Map<String, String> base = Map.of(
                "A", "あ",
                "B", "い"
        );
        Map<String, String> map = new HashMap<>(base);

        map.put("C", "う");
        System.out.println(map); // {A=あ, B=い, C=う}
    }
}
Java

ここでの重要ポイントは、「外から見える型は Map、実体は HashMap」というスタイルを守りつつ、
「初期値入りの可変Map」を安全に作っていることです。


順序を保ちたいときは LinkedHashMap で初期化する

「putした順番で取り出したい」要件に応える

HashMap は順序を保証しません。
「登録した順番でループしたい」「画面に出す順番を固定したい」といった要件がある場合は、
LinkedHashMap を使って初期化します。

import java.util.LinkedHashMap;
import java.util.Map;

public class MapInitOrdered {

    public static void main(String[] args) {
        Map<String, String> ordered = new LinkedHashMap<>();
        ordered.put("1", "一番目");
        ordered.put("2", "二番目");
        ordered.put("3", "三番目");

        for (Map.Entry<String, String> e : ordered.entrySet()) {
            System.out.println(e.getKey() + " -> " + e.getValue());
        }
        // 1 -> 一番目
        // 2 -> 二番目
        // 3 -> 三番目
    }
}
Java

ここでの重要ポイントは、「順序を保つかどうかも“初期化の時点で決まる”」ということです。
後から「やっぱり順番が必要だった」と気づいても、
Mapの実装を変えるのは大きな影響が出ることがあります。
最初に「このMapは順序が意味を持つか?」を考えておく癖をつけると、設計が安定します。


null を返さない Map初期化ユーティリティという発想

「空のMapを返す」ことをルールにするとコードが楽になる

Listと同じく、Mapでもよくある悪いパターンが
「該当がなければ null を返す」というメソッドです。

// 悪い例
Map<String, String> findSettings() {
    if (条件に合うものがなければ) {
        return null;
    }
    ...
}
Java

これをやると、呼び出し側は毎回こう書く必要が出てきます。

Map<String, String> settings = findSettings();
if (settings != null) {
    String value = settings.get("key");
    ...
}
Java

null チェックの書き忘れがバグの温床になります。

そこで、「Mapを返すメソッドは、要素がなくても必ず空のMapを返す」というルールにしてしまうと、
呼び出し側がとても楽になります。

import java.util.Collections;
import java.util.Map;

public final class MapUtils {

    private MapUtils() {}

    public static <K, V> Map<K, V> emptyIfNull(Map<K, V> map) {
        return (map == null) ? Collections.emptyMap() : map;
    }
}
Java

使い方はこうです。

Map<String, String> settings = MapUtils.emptyIfNull(findSettings());
String value = settings.get("key"); // nullチェック不要(見つからなければ単にnullが返る)
Java

ここでの重要ポイントは、「null を“空のMap”に正規化する」という発想です。
これにより、「nullかもしれないMap」と「空のMap」を区別しなくてよくなり、
コードの分岐が減ります。


まとめ:Map初期化で本当に意識してほしいこと

Map初期化は、単なる new HashMap<>()Map.of(...) の話ではなく、
「このMapは変わるのか、変わらないのか」「順序は意味を持つのか」「nullを返すのか、空を返すのか」
といった設計の話です。

可変Mapが欲しいなら new HashMap<>() を基本形にする。
定数的な対応表なら Map.of(...) で不変Mapにしておく。
初期値入りの可変Mapが欲しいなら new HashMap<>(Map.of(...)) のようにコピーする。
順序が大事なら最初から LinkedHashMap で初期化する。
メソッドの戻り値としては「nullではなく空のMapを返す」ルールにしておく。

もしあなたのコードのどこかに、
if (map == null) { ... } のようなnullチェックが何度も出てきているなら、
それを「Map初期化とnull正規化のユーティリティ」で置き換えられないか、一度眺めてみてください。

その小さな意識の変化が、
「コレクションの性質を理解して、安定した業務コードを書けるエンジニア」への、
確かな一歩になります。

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