今回は、実際のコードでほぼ必ず登場する「コレクション」と「ジェネリクス」の基本を紹介します。List<String>のような山括弧付きの書き方の意味も、あわせて整理します。
対象読者
- クラス・継承・例外処理といったJavaの基本を理解している方
-
List・Set・Mapの違いと、それぞれの代表的な実装クラスを整理しておきたい方 -
List<String>のような山括弧(ジェネリクス)の意味がまだよく分かっていない方
コレクションを使った具体的なアルゴリズムの実装や、ワイルドカード(? extends Tなど)を使った高度なジェネリクスの話までは扱いません。あくまで基本の型と使い方の整理に絞っています。
検証環境
Java 25(LTS、2025年9月リリース)を前提にしています。2026年3月にリリースされたJava 26は非LTSでサポート期間が6か月に限定されている1ため、学習用途で環境を作るなら、現行LTSであるJava 25を使うのが無難です。
コレクションフレームワークとは
コレクションフレームワークは、複数の要素をまとめて扱うためのデータ構造(コレクション)を、統一された方法で操作するための仕組みです。Oracleの公式チュートリアルでは、インターフェース(データ型の定義)・実装(具体的なデータ構造)・アルゴリズム(検索やソートなどの処理)という3つの要素から構成されると説明されています2。
コレクションフレームワークの中心にあるのがCollectionインターフェースで、List・Set・Queueといった、より具体的な性質を持つインターフェースの親にあたります3。MapはCollectionとは別系統のインターフェースですが、同じフレームワークの一部として扱われます。
以下、代表的な3つのインターフェース(List・Set・Map)を順に見ていきます。
List:順序があり、重複を許可する
Listは、要素の挿入順序が保持され、重複した要素も許可されるコレクションです4。配列のように、インデックスを指定して要素を取得・追加・削除できます。
List<String> names = new ArrayList<>();
names.add("ポチ");
names.add("ハチ");
names.add("ポチ"); // 重複OK
System.out.println(names.get(0)); // ポチ
System.out.println(names.size()); // 3
代表的な実装クラスにはArrayListとLinkedListがあります。公式チュートリアルでは、多くの場合はArrayListが推奨され、LinkedListはリストの中間への挿入・削除が多い場合など、特定の状況で有利だと説明されています4。
Set:重複を許可しない
Setは、数学の「集合」をモデルにしたコレクションで、重複した要素を持てません5。同じ要素をaddしても、2つ目以降は無視されます。
Set<String> uniqueNames = new HashSet<>();
uniqueNames.add("ポチ");
uniqueNames.add("ハチ");
uniqueNames.add("ポチ"); // 無視される
System.out.println(uniqueNames.size()); // 2
代表的な実装クラスは次の3つです5。
| 実装クラス | 特徴 |
|---|---|
HashSet |
ハッシュテーブルで保存する。反復時の順序は保証されないが、最も高速 |
LinkedHashSet |
HashSetに加えて、挿入した順序を保持する |
TreeSet |
要素の値に基づいて並び替えられた状態を保持する。他の2つよりは低速 |
Map:キーと値の組を扱う
Mapは、Collectionとは別系統のインターフェースで、キーと値の組(ペア)を扱います。1つのキーには最大1つの値しか対応させられません6。
Map<String, Integer> ageByName = new HashMap<>();
ageByName.put("ポチ", 3);
ageByName.put("ハチ", 5);
System.out.println(ageByName.get("ポチ")); // 3
Setと同様に、代表的な実装クラスとしてHashMap・LinkedHashMap・TreeMapがあり、それぞれ順序なし・挿入順・キーのソート順という違いがあります6。Mapの中身をループで取り出す場合は、keySet()・values()・entrySet()という3種類の「ビュー」を使います。
for (Map.Entry<String, Integer> entry : ageByName.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue() + "歳");
}
ジェネリクスとは何か
ここまでのコードにはList<String>やMap<String, Integer>のように、山括弧< >で型を指定する書き方が繰り返し出てきました。これがジェネリクスです。ジェネリクスを使うと、クラスやメソッドを定義する際に、扱うデータ型そのものを「パラメータ」として指定できます7。
ジェネリクスが導入される前は、コレクションは中身の型を区別せずにObjectとして扱っていたため、取り出すたびに明示的なキャストが必要でした。
// ジェネリクスなし(Java 5より前のイメージ)
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0); // キャストが必要
// ジェネリクスあり
List<String> list = new ArrayList<>();
list.add("hello");
String s = list.get(0); // キャスト不要
公式チュートリアルでは、ジェネリクスの利点として「コンパイル時の強い型チェック」「キャストの排除」「型安全な汎用アルゴリズムの実装」の3点が挙げられています7。List<String>と書いておけば、誤ってIntegerを追加しようとした時点でコンパイルエラーになり、実行時になって初めて型の不一致に気づく、という事故を防げます。
自分でジェネリッククラスを作る
ジェネリクスはListやMapのような標準クラスだけでなく、自分で定義するクラスにも使えます8。
public class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}
Box<String> stringBox = new Box<>();
stringBox.set("ポチ");
String name = stringBox.get(); // キャスト不要
Box<Integer> intBox = new Box<>();
intBox.set(3);
Box<T>のTは型パラメータで、慣習としてT(Type)・E(Element)・K(Key)・V(Value)のように、用途に応じた1文字の大文字が使われます8。new Box<>()のように、右辺の型引数を省略して<>とだけ書く書き方は「ダイアモンド演算子」と呼ばれ、Java SE 7以降、左辺の型からコンパイラが型を推論してくれます8。
まとめ
- コレクションフレームワークは、
List・Set・Mapといったインターフェースと、その実装クラス群からなる統一的な仕組み -
Listは順序あり・重複可(ArrayList・LinkedList) -
Setは重複不可(HashSet・LinkedHashSet・TreeSet) -
Mapはキーと値の組を扱う(HashMap・LinkedHashMap・TreeMap) - ジェネリクスは、クラスやメソッドの型を「パラメータ」として扱う仕組みで、コンパイル時の型チェックとキャストの排除を実現する
-
Box<T>のように、自分で定義するクラスにもジェネリクスを使える。new Box<>()のダイアモンド演算子で型引数を省略できる
List<String>のような書き方を「決まり文句」として覚えるのではなく、「Listというジェネリッククラスに、Stringという型引数を渡している」と理解しておくと、標準ライブラリの型シグネチャも読み解きやすくなります。
脚注
参考資料
- Introduction to Collections | The Java™ Tutorials (Oracle)
- The Collection Interface | The Java™ Tutorials (Oracle)
- The List Interface | The Java™ Tutorials (Oracle)
- The Set Interface | The Java™ Tutorials (Oracle)
- The Map Interface | The Java™ Tutorials (Oracle)
- Why Use Generics? | The Java™ Tutorials (Oracle)
- Generic Types | The Java™ Tutorials (Oracle)
- Java 26 正式リリース — ラーゲイト株式会社
-
Java 26は2026年3月18日にリリースされた非LTS版で、サポート期間は6か月間(2026年9月まで)。現行LTSはJava 25(2025年9月リリース)。詳細はJava 26 正式リリース — ラーゲイト株式会社を参照。 ↩
-
Introduction to Collections | The Java™ Tutorials (Oracle) ↩