1. はじめに
かつて私たちは「無限配列」— リストについて学びました。ここでは知識をさらに深めるために、「クラシックな」配列とは何かをもう一度考えてみましょう。よく見ると、配列は固定個数の仕切りがある工具箱のようなものです。例えば、箱に 10 個の仕切りがあるとします。そこに 11 個目の工具が増えたら、どうしますか? 新しい箱を買うしかありません! 同じように、従来の配列はサイズが固定で、作成後に長さは変わりません。
要素を追加・削除したい場合は、新しい配列を作って手作業でデータをコピーする必要があります。配列ではインデックスで要素を素早く見つけられますが、配列の途中に挿入するには「右にずらす」必要があり、削除するには「左にずらす」必要があります。これは遅くて不便です。さらに、配列自体は追加の「ロジック」を持ちません。単に要素の箱を持っているだけなので、ソートや内容検索、一意性の確認は外部の手段で行わなければなりません。
例: 学生の動的リスト
例えば、クラス内の学生を管理するアプリを書いているとします。最初は 5 人、次に 1 人増え、誰かが抜けることもあります。配列だと次のようになります:
String[] students = new String[5];
students[0] = "イワン";
students[1] = "マリア";
// などなど...
// おっと、学生がもう一人来た
// 新しい配列を作成する必要があります!
String[] newStudents = new String[6];
for (int i = 0; i < students.length; i++) {
newStudents[i] = students[i];
}
newStudents[5] = "アレクセイ";
students = newStudents;
便利でしょうか? 正直、いいえ。こんな操作がたくさんあったら? もっと便利なものが欲しくなります…
2. コレクションとは?
コレクション とは、他のオブジェクト(要素)をまとめて保持するためのコンテナとして機能するオブジェクトです。コレクションは要素の追加・削除・走査に加え、検索・ソート・フィルタリングなどの操作も可能にします。
Java では、すべてのコレクションがインタフェース Collection(もしくは、マップの場合は Map)を実装または継承します。コレクションは単なる「寄せ集め」ではなく、要素を扱うための便利でよく考えられたメソッド群を備えた構造です。
なぜコレクションはオブジェクトなのか?
コレクションはクラスとして実装されているため、任意のオブジェクトのコレクションを作成でき、組み合わせたり、継承や拡張ができ、自分のクラスやメソッドで利用できます。
例:
import java.util.ArrayList;
import java.util.List;
List<String> students = new ArrayList<>();
students.add("イワン");
students.add("マリア");
students.add("アレクセイ");
ほら! もう配列サイズを気にせず、いくらでも学生を追加できます。
3. コレクションが解決する典型的なタスク
コレクションはデータ操作のためのスイスアーミーナイフです。以下のような課題を解決できます:
- 動的なデータリストの保持: 例: 学生リスト、スケジューラのタスク、チャットのメッセージ。
- 検索とフィルタリング: 要素を素早く見つける、存在を確認する、条件に合う要素を取得する。
- ソート: 任意の基準で簡単に並べ替える。
- 要素の追加・削除: 配列を手動でコピーすることなく、任意の位置に挿入・削除できる。
- キーによるグルーピング: 例: 名前に電話番号を対応させる電話帳。
- 一意性の保証: 例: テキスト中のユニークな単語の集合。
例: 電話帳
配列の場合:
- 名前から番号をどう探す? 配列を走査して名前を比較する必要がある。
- 新しいペアをどう追加する? 配列を拡張する必要がある。
- 名前の重複をどう防ぐ? さらに難しい。
コレクションの場合:
- Map<String, String> を使えば、すべて「箱から出してすぐ」に動く。
4. 主なコレクションの種類
Java のコレクションは大きく 3 つに分かれます:
| コレクションの種類 | インタフェース/クラス | 用途 |
|---|---|---|
| リスト | List, ArrayList | 順序付きで重複可、インデックスでアクセス可能 |
| セット | Set, HashSet | 一意な要素のみ保持、順序は保証されない |
| マップ | Map, HashMap | キーと値のペアを保持、キーによる高速検索 |
リスト (List)
- 順序付きのコレクションで、重複を許可します。
- インデックスで要素を取得できます。
- 例: ArrayList、LinkedList。
セット (Set)
- 一意な要素のみを保持します。
- インデックスによるアクセスはありません。
- 例: HashSet、TreeSet。
マップ (Map)
- キーと値のペアを保持します。
- キーによる高速検索が可能です。
- 例: HashMap、TreeMap。
ビジュアル図(かなり大雑把):
+------------------+ +-------------------+ +---------------------+
| List | | Set | | Map |
|------------------| |-------------------| |---------------------|
| [a, b, c, d, a] | | {a, b, c, d} | | {a=1, b=2, c=3} |
| インデックス: あり | | インデックス: なし | | キーで検索 |
| 重複: あり | | 重複: なし | | キーは一意 |
+------------------+ +-------------------+ +---------------------+
5. 便利なポイント
どのコレクションを使うべきか?
List — 要素の順序が重要、重複が必要、インデックスでのアクセスが必要な場合(例: タスクリスト、メッセージ履歴)。
Set — 一意な要素だけが必要で、順序は重要でない場合(例: ユーザーのユニーク集合)。
Map — キーと値を対応付けたい場合(例: 住所録。名前=キー、電話=値)。
身近な例え
List — 食堂の行列:先に来た人が先に対応。何度でも並べる(重複)。
Set — パーティーの招待客リスト:各ゲストは 1 回だけ(ユニーク)。
Map — アドレス帳:それぞれの名前に電話番号がある。
簡単な早見表: コレクション vs 配列
| 配列 (int[]) | コレクション (List<Integer>) | |
|---|---|---|
| サイズ | 固定 | 可変(動的) |
| 要素の追加 | 不便 | 簡単: add() |
| 要素の削除 | 不便 | 簡単: remove() |
| 値による検索 | 手動で走査 | メソッド: contains() など |
| ソート | Arrays.sort() 経由 | Collections.sort() 経由、コレクションのメソッド |
| 一意性のサポート | なし | Set を使用 |
| キーと値のペア | なし | Map を使用 |
6. コレクションと OOP の関係
コレクションは特定のインタフェース(List、Set、Map)を実装するオブジェクトです。つまり、次のことが可能です:
- 任意のオブジェクト(自作クラスのインスタンスを含む)をコレクションに保持できる。
- コレクションのコレクションを作成できる(例: リストのリスト)。
- メソッドの引数や戻り値としてコレクションを使える。
- 継承やコンポジションでコレクションの機能を拡張できる。
例: 自作クラスのオブジェクトのコレクション
import java.util.ArrayList;
import java.util.List;
class Student {
String name;
int age;
// コンストラクタ、ゲッター/セッターなど
}
public class Main {
public static void main(String[] args) {
List<Student> group = new ArrayList<>();
group.add(new Student("イワン", 20));
group.add(new Student("マリア", 21));
// などなど...
}
}
7. コレクション操作でのよくあるミス
ミス1: 型指定なしのコレクション(raw types)の使用。
ArrayList list = new ArrayList() のように書くと、どんなオブジェクトでも(文字列や数値が混在しても)追加でき、コンパイラは文句を言いません。しかし、取り出して必要な型にキャストする段階で実行時エラー(ClassCastException)を招く可能性があります。常にジェネリクスを使いましょう: ArrayList<String> list = new ArrayList<>()。
ミス2: 必要なクラスを import し忘れる。
「cannot find symbol」というエラーが出たら、ファイル先頭に import java.util.ArrayList; など、対象コレクションに必要な import があるか確認してください。
ミス3: コレクションと配列の混同。
コレクションは配列ではありません! コレクションにはフィールド length はなく、代わりに size() メソッドを使います。配列には add() メソッドはありませんし、コレクションにはインデックスアクセス用の [] 演算子はありません(リストは get(index) でアクセスします)。
ミス4: 要素の順序が常に保持されると思い込む。
Set や Map を使う場合、順序は保証されません(LinkedHashSet や TreeMap のような特別な実装を使う場合を除く)。順序が必要なら List か、適切なコレクションを使いましょう。
ミス5: プリミティブ型をコレクションで使う。
コレクションはオブジェクトしか保持できません。つまり、List<int> は作れず、List<Integer> だけです。ラッパークラスを忘れずに!
GO TO FULL VERSION