Javaでデータを扱う際、これら5つの「入れ物」の使い分けがプログラミングの質を左右します。特に「不変(Immutable)」と「変更可能(Mutable)」の違いは、バグを防ぐ上で非常に重要です。
1. 特徴の比較まとめ¶
| 種類 | 順序 | 重複 | 追加・削除 | 特徴・用途 |
|---|---|---|---|---|
| 配列 | あり | OK | 不可 | 固定長。速度重視。基本型(int等)が使える。 |
| 不変リスト | あり | OK | 不可 | 読み取り専用。安全性が高い(定数など)。 |
| 変更可能リスト | あり | OK | 自由 | 最も一般的。サイズが動的に変わる。 |
| Set | なし | NG | 自由 | 重複を許さない。存在チェックが高速。 |
| Map | なし | KeyはNG | 自由 | キーと値のペア。辞書形式での検索に最適。 |
2. サンプルコード¶
それぞれの宣言方法と、操作の可否を確認してみましょう。
配列 (Array) & 不変リスト (Immutable List)¶
これらは一度作るとサイズを変更できません(不変リストは中身の書き換えも不可)。
// --- 配列 ---
String[] array = {"A", "B", "C"};
array[0] = "Z"; // 上書きはできるが、追加(add)はできない
// --- 不変リスト (Java 9+) ---
List<String> immutableList = List.of("A", "B", "C");
// immutableList.add("D"); // エラー(UnsupportedOperationException)
// immutableList.set(0, "Z"); // エラー
変更可能リスト (Mutable List) & Set¶
データの追加や削除が頻繁にある場合に使います。
// --- 変更可能リスト ---
List<String> mutableList = new ArrayList<>(Arrays.asList("A", "B"));
mutableList.add("C"); // OK: [A, B, C]
mutableList.remove(0); // OK: [B, C]
// --- Set (重複なし) ---
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Apple"); // 重複しているので無視される
System.out.println(set.size()); // 1
Map (Key-Value)¶
特定の「鍵」を使ってデータを取り出します。
// --- Map ---
Map<String, Integer> scores = new HashMap<>();
scores.put("田中", 80);
scores.put("佐藤", 95);
System.out.println(scores.get("田中")); // 80 を表示
3. 実践的な使い分けのポイント¶
- 「定数」として定義したい時
List.of(...)で**不変リスト**を作ります。誤ってプログラムの途中で中身が書き換わるのを防げます。 - データの「検索」を高速化したい時
数万件のデータから特定のIDがあるか調べるとき、
Listでcontainsを使うと遅いですが、Setなら一瞬()で終わります。 - Stream APIとの組み合わせ
Streamで加工した結果を
toList()で受け取ると**不変リスト**になり、collect(Collectors.toList())で受け取ると通常は**変更可能リスト**になります。
次は、これらのコレクションを Stream API で一気に変換したり、Map に集計したりする「実践的なデータ処理」に挑戦してみますか?
不変リスト、変更可能リスト¶
Javaにおける「初期化のみで変更不可能なリスト(不変リスト)」と「変更可能なリスト」の作成方法は、Javaのバージョンによって大きく進化しています。
特にJava Gold試験では、 どのメソッドを使うと「固定サイズ(値の書き換えは可能)」になり、どれを使うと「完全不変(読み取り専用)」になるか の区別が非常に重要です。
1. 変更不可能な配列(リスト)の宣言¶
これらは、一度宣言すると要素の追加(add)や削除(remove)ができず、実行時に UnsupportedOperationException が発生します。
A. 完全不変リスト(Java 9以降:推奨)¶
要素の追加・削除だけでなく、 既存要素の書き換えも不可 能です。
// 最も一般的な書き方
List<String> immutableList = List.of("A", "B", "C");
// immutableList.add("D"); // 例外発生
// immutableList.set(0, "Z"); // 例外発生
B. 固定サイズリスト(Java 8以前からの書き方)¶
Arrays.asList で生成すると、 追加・削除は不可 ですが、 既存要素の書き換え(set)は可能 という特殊な状態になります。
List<String> fixedSizeList = Arrays.asList("A", "B", "C");
// fixedSizeList.add("D"); // 例外発生(追加はできない)
fixedSizeList.set(0, "Z"); // 成功([Z, B, C] に書き換わる)
2. 変更可能な配列(ArrayList)の宣言¶
要素を自由に追加・削除・変更できる一般的なリストです。
A. 初期化と同時に値をいれる(Java 9以降)¶
List.of などで作った不変リストをコンストラクタに渡して、変更可能な ArrayList を生成します。
List<String> mutableList = new ArrayList<>(List.of("A", "B", "C"));
mutableList.add("D"); // 成功
mutableList.remove(0); // 成功
mutableList.set(0, "Z"); // 成功
B. 空で宣言して後から追加する¶
最も基本的な書き方です。
まとめ・比較表¶
| メソッド | 追加・削除 | 値の書き換え(set) |
特徴 |
|---|---|---|---|
List.of(...) |
不可 | 不可 | 完全不変。Java 9以降の標準。 |
Arrays.asList(...) |
不可 | 可能 | 固定サイズ。元の配列と連動する。 |
new ArrayList<>(...) |
可能 | 可能 | 完全可変。実務で最も多用される。 |
Collections.unmodifiableList(...) |
不可 | 不可 | 既存のListを読み取り専用にラップする。 |
💡 Java Gold 試験対策のヒント¶
試験では以下のようなコードが出題され、実行結果を問われます。
「Arrays.asList はサイズは変えられないが、中身の入れ替えはできる」という点は非常に狙われやすいポイントです。
次は、これらのリストを「Stream APIで処理した後に再び不変リストに戻す方法」などについて詳しく解説しましょうか?