【Java学習|実務向け】Java 9以降の不変Map生成を使いこなす:Map.of(), Map.ofEntries(), Map.copyOf()の使い分け

導入

Java 9から導入されたMapのファクトリメソッド群は、これまで冗長だった初期化処理を劇的に簡潔にしました。実務において、定数定義やテストデータの作成、APIレスポンスの構築などでこれらのメソッドを活用することは、コードの可読性を高めるだけでなく、予期せぬ変更を防ぐ「不変性(Immutable)」を担保する上でも非常に重要です。本稿では、これら3つのメソッドの適切な使い分けと実装上の注意点を解説します。

基礎知識

Javaのコレクションフレームワークにおける不変コレクションとは、作成後に要素の追加・削除・変更ができないコレクションを指します。

  • Map.of(): 少数の固定的なキーと値のペアを生成するのに適した可変引数メソッドです。
  • Map.ofEntries(): Map.Entryオブジェクトを使用して生成します。Map.of()の引数上限(10個)を超える場合や、動的にエントリを構築する場合に使用します。
  • Map.copyOf(): 既存のMapをコピーして不変Mapを作成します。nullの混入を防ぐなど、防御的コピーに最適です。

実装/解決策

実務では、用途に応じてこれらを使い分けるのがベストプラクティスです。
1. 要素数が少なく、定数として定義する場合は Map.of()
2. 要素数が多い場合や、Map.Entryを動的に生成するロジックがある場合は Map.ofEntries()
3. 外部から受け取ったMapを不変として扱いたい(副作用を防ぎたい)場合は Map.copyOf() を使用します。

サンプルプログラム

以下のコードは、実務でよく遭遇するユースケースをまとめたものです。

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

public class MapExample {
public static void main(String[] args) {
// 1. Map.of(): 少数の要素を簡潔に定義
Map config = Map.of(“env”, “prod”, “version”, “1.0.0”);
System.out.println(“Config: ” + config);

// 2. Map.ofEntries(): 10個を超える要素や、動的なエントリ生成
Map statusMap = Map.ofEntries(
Map.entry(200, “OK”),
Map.entry(404, “Not Found”),
Map.entry(500, “Internal Server Error”)
);
System.out.println(“Status: ” + statusMap);

// 3. Map.copyOf(): 既存Mapの防御的コピー
Map mutableMap = new HashMap<>();
mutableMap.put(“key1”, “value1”);

// 外部から渡されたMapを不変にして保持する(副作用防止)
Map immutableMap = Map.copyOf(mutableMap);
System.out.println(“Immutable: ” + immutableMap);
}
}

応用・注意点

現場でこれらのメソッドを使用する際に、必ず押さえておくべき注意点が3つあります。

1. nullの禁止: これらのメソッドで生成されるMapは、キーにも値にも null を許容しません。もし null を含めてしまうと NullPointerException が発生します。データが null になる可能性がある場合は、事前にフィルタリングが必要です。
2. 変更不可の性質: これらのメソッドで作成されたMapに対して put() や remove() を実行すると、UnsupportedOperationException がスローされます。意図せず値を書き換えるロジックが残っていないか注意してください。
3. copyOf()の最適化: Map.copyOf() は、引数がすでに「不変Map」である場合、内部的にコピーを作成せずに元のインスタンスをそのまま返すという最適化が行われています。これにより、パフォーマンスへの影響を最小限に抑えつつ、安全なコードを記述できます。

不変コレクションを積極的に採用することで、マルチスレッド環境下での安全性向上や、意図しないデータ書き換えバグの抑制に繋がります。ぜひ積極的に活用してください。

コメント

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