1. 導入:なぜコレクションの「状態」を意識すべきか
Java開発において、ListやMapを扱う際に「このコレクションは後から変更して良いのか?」という設計意図が不明確だと、意図しない副作用(バグ)や並行処理時の不整合が発生します。特にAPI設計やドメインモデルにおいて、状態の定義(Modifiable, Unmodifiable, Immutable)を厳密に使い分けることは、堅牢なコードを書くための第一歩です。本記事では、これらの違いと実務での使い分けを解説します。
2. 基礎知識:3つの状態の定義
Javaのコレクションを理解する上で、以下の3つの区分を明確にしましょう。
Modifiable(可変): 要素の追加・削除・置換が可能な状態。デフォルトのArrayListやHashMapなどが該当します。
Unmodifiable(変更不可): コレクションへの変更操作(addやremove)を呼び出すと、UnsupportedOperationExceptionが発生する状態。ただし、内部の元のコレクションが変更されれば、その影響を受けます。
Immutable(不変): 生成後に状態が一切変化しないこと。外部から変更されることがなく、スレッドセーフであるため、現代のJava開発では強く推奨されます。
3. 実装と解決策
Java 9以降、標準APIでこれらのコレクションを生成する方法が整備されました。
List.of() / Set.of() / Map.of(): これらはImmutableなコレクションを生成します。要素の追加・削除はもちろん、nullの保持も許可されません。
Collections.unmodifiableList(): 既存の可変コレクションをラップして「変更不可」にします。元のコレクションが変更されると、こちらにも影響が出る点に注意が必要です。
実務では、メソッドの引数や戻り値として「変更してほしくない」場合は、可能な限りImmutableなコレクションを返す設計を心がけましょう。
4. サンプルプログラム
以下のコードで、各状態の挙動と注意点を確認してください。
import java.util.;
public class CollectionExample {
public static void main(String[] args) {
// 1. Modifiable: 自由に操作可能
List<String> mutableList = new ArrayList<>(Arrays.asList("A", "B"));
mutableList.add("C");
// 2. Unmodifiable (View): 元のリストが変更されると影響を受ける
List<String> unmodifiableView = Collections.unmodifiableList(mutableList);
System.out.println("View: " + unmodifiableView); // [A, B, C]
mutableList.add("D"); // 元を変更すると...
System.out.println("View after source change: " + unmodifiableView); // [A, B, C, D]
// 3. Immutable: 生成後に一切変化しない(推奨)
List<String> immutableList = List.of("A", "B", "C");
try {
immutableList.add("D"); // ここで UnsupportedOperationException が発生
} catch (UnsupportedOperationException e) {
System.out.println("Immutableは変更不可です");
}
}
}
5. 応用・注意点:現場で陥りやすい罠
nullの扱いに注意: List.of()などのImmutableなファクトリメソッドは、nullを格納しようとするとNullPointerExceptionを投げます。DBの検索結果など、nullが含まれる可能性がある場合は、Stream APIのfilter(Objects::nonNull)などを活用して除去してから生成してください。
Sequenced Collectionsの活用: Java 21からはLinkedHashSetやArrayListがSequencedCollectionインターフェースを実装しました。これにより、先頭や末尾へのアクセスが容易になっています。これらも「順序を保持する」という特性を理解した上で、Immutableなコピーを返す設計にすると、デバッグが非常に楽になります。
まとめ:
・外部に公開するデータは可能な限りImmutableにする。
・「読み取り専用」であることを明示したい場合はUnmodifiableViewを使う。
・スレッドセーフを意識するなら、迷わずImmutableを選択する。
この指針を持つだけで、コードの品質と保守性は一段階向上します。ぜひプロジェクトで意識してみてください。

コメント