Javaコレクションフレームワーク完全攻略!List・Set・Mapの違いと使い分けを徹底解説
生徒
「Javaでたくさんのデータをまとめて扱いたいとき、ListとかSetとかいろいろあって、どれを使えばいいか迷ってしまいます。」
先生
「それはJavaエンジニアが最初に通る道ですね。Javaには『コレクションフレームワーク』という便利な仕組みがあり、データの性質に合わせてList、Set、Mapを使い分けるのが基本です。」
生徒
「それぞれ、どんな特徴があるんですか?具体的にどう使い分ければいいのか知りたいです!」
先生
「それでは、初心者の方でもイメージしやすいように、それぞれの違いと用途を詳しく解説していきましょう!」
1. Javaコレクションフレームワークの全体像
Javaのプログラミングにおいて、複数のオブジェクトをまとめて管理するための仕組みを「コレクションフレームワーク」と呼びます。配列も複数のデータを扱えますが、配列は作成時にサイズを決めなければならず、後から要素を増やしたり減らしたりするのが大変です。一方、コレクションフレームワークはデータの増減に柔軟に対応でき、検索や並べ替えなどの便利な機能が豊富に用意されています。
主要なインターフェースは大きく分けて3つあります。それが「List(リスト)」「Set(セット)」「Map(マップ)」です。これらはデータの持ち方やルールが根本的に異なります。例えば、出席名簿のように順番が大事なもの、おみくじの景品一覧のように重複を許さないもの、辞書のようにキーワードと内容がセットになっているものなど、現実世界のデータの形式に合わせて最適なものを選びます。
2. Listインターフェースの特徴と使い方
List(リスト)は、もっとも頻繁に使われるコレクションです。その最大の特徴は「順序を保持すること」と「重複を許可すること」です。要素を追加した順番に並び、インデックス(添え字)を使って「0番目の要素」「1番目の要素」というようにアクセスできます。中身が同じデータが複数あっても問題ありません。
代表的な実装クラスにはArrayListがあります。これは内部的に配列を使ってデータを管理しており、データの読み取りが非常に高速です。日常的な開発では、このArrayListを選択しておけば間違いありません。買い物リストや履歴データ、検索結果の表示など、順番に意味があるデータ構造に最適です。要素を末尾に追加する操作は得意ですが、途中に要素を挿入したり削除したりする場合は、後ろの要素をずらす必要があるため少し時間がかかります。
import java.util.ArrayList;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
// ArrayListの作成
List<String> shoppingList = new ArrayList<>();
// 要素の追加
shoppingList.add("りんご");
shoppingList.add("バナナ");
shoppingList.add("りんご"); // 重複OK
// データの表示(追加した順に表示される)
for (String item : shoppingList) {
System.out.println("商品: " + item);
}
}
}
商品: りんご
商品: バナナ
商品: りんご
3. Setインターフェースの特徴と使い方
Set(セット)は「集合」を扱うためのコレクションです。Listとの最大の違いは「重複を許さないこと」です。同じ要素を二度追加しようとしても、Set内には一つしか存在できません。また、標準的なHashSetなどは「順序を保証しない」という特徴もあります。追加した順番とはバラバラにデータが格納されるため、インデックスで「○番目」と指定して取り出すことはできません。
用途としては、ユーザーIDの一覧や、アンケートの回答選択肢の抽出など、「ユニークな値だけを集めたいとき」に非常に強力です。また、大量のデータの中から「ある値が含まれているか」をチェックする速度がListよりも圧倒的に速いというメリットもあります。例えば、ブラックリストに特定のユーザーが含まれているか瞬時に判定したい場合などに活躍します。実装クラスにはHashSetのほか、順序を保持するLinkedHashSetや、値を自動で並べ替えるTreeSetがあります。
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
// HashSetの作成
Set<Integer> userIds = new HashSet<>();
// 要素の追加
userIds.add(101);
userIds.add(102);
userIds.add(101); // 重複しているため無視される
System.out.println("登録ユーザー数: " + userIds.size());
// 特定のIDが含まれているか確認
if (userIds.contains(101)) {
System.out.println("ユーザー101は存在します。");
}
}
}
登録ユーザー数: 2
ユーザー101は存在します。
4. Mapインターフェースの特徴と使い方
Map(マップ)は、ListやSetとは少し毛色が異なります。これは「キー(Key)」と「値(Value)」をペアにして保存する形式です。電話帳の名前(キー)と電話番号(値)、あるいは商品コード(キー)と商品名(値)のような関係性をイメージしてください。Mapの最大の特徴は、キーを使って値を一瞬で検索できることです。
Mapのルールとして「キーの重複は禁止」ですが、「値の重複は許可」されています。もし既に存在するキーで別の値を保存しようとすると、古い値は上書きされます。もっとも一般的な実装クラスはHashMapです。設定ファイルの情報を保持したり、データベースから取得したレコードをIDで管理したりする際に非常に重宝します。順序を保持したい場合はLinkedHashMapを使い、キーでソートしたい場合はTreeMapを使います。プログラミングの実務ではListと同じくらい多用される非常に重要なクラスです。
import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
// HashMapの作成(キーはString、値はInteger)
Map<String, Integer> fruitPrices = new HashMap<>();
// データの登録
fruitPrices.put("りんご", 150);
fruitPrices.put("メロン", 2000);
fruitPrices.put("バナナ", 100);
// キーを指定して値を取得
String target = "メロン";
System.out.println(target + "の価格は" + fruitPrices.get(target) + "円です。");
// 全てのキーと値のペアを表示
for (Map.Entry<String, Integer> entry : fruitPrices.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue() + "円");
}
}
}
メロンの価格は2000円です。
バナナ : 100円
りんご : 150円
メロン : 2000円
5. 結局どれを使うべき?用途別の比較表
ここまで紹介したList、Set、Mapのどれを使うべきか判断するための基準を整理しました。初心者のうちは、データの「並び順」が必要か、それとも「値の重複」を避けたいのか、あるいは「特定のキーワードで検索」したいのかを自分に問いかけてみてください。
| 項目 | List (ArrayList) | Set (HashSet) | Map (HashMap) |
|---|---|---|---|
| データの持ち方 | 単一の値の列 | 単一の値の集合 | キーと値のペア |
| 順序 | あり(追加順) | なし | なし |
| 重複 | 許可する | 許可しない(一意) | キーは不可・値は可 |
| 主な用途 | 順番通りに処理したい、履歴の管理 | 重複を排除したい、存在チェック | キーワードで素早く検索したい |
| アクセス方法 | インデックス (0, 1, 2...) | Iteratorや拡張for文 | キー (Key) を指定 |
6. コレクションを扱う際の注意点とジェネリクス
Javaのコレクションを使用する際に必ず覚えておきたいのが「ジェネリクス(Generics)」です。これは、そのコレクションが「何の型のオブジェクトを扱うか」を指定する仕組みです。例えば、List<String>と書けば、そのリストには文字列しか入れられなくなります。これにより、間違えて数値を入れてしまうようなミスを防ぐことができ、プログラムの安全性が高まります。
また、コレクションは「オブジェクト(参照型)」しか扱えないという制約があります。intやdoubleなどの基本データ型をそのまま入れることはできません。しかし、Javaには「オートボクシング」という機能があるため、intを入れると自動的にIntegerクラスに変換してくれます。初心者の方は、List<int>ではなくList<Integer>と書く必要があることだけ覚えておけば大丈夫です。これらのコレクションを自由自在に使いこなせるようになると、複雑なアルゴリズムやデータ処理も驚くほどシンプルに記述できるようになります。まずは基本のArrayListから触ってみて、徐々にSetやMapの便利さを体感していきましょう。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AdvancedListExample {
public static void main(String[] args) {
// 数値を扱うList
List<Integer> scores = new ArrayList<>();
scores.add(85);
scores.add(92);
scores.add(78);
// データの並び替え(ソート)
Collections.sort(scores);
System.out.println("昇順に並び替えたスコア:");
for (int s : scores) {
System.out.println(s);
}
// 最大値の取得
int max = Collections.max(scores);
System.out.println("最高点: " + max);
}
}
昇順に並び替えたスコア:
78
85
92
最高点: 92