この記事の要点
• HashSet は重複を許さない集合(Set)を実現するクラス
• `add()` で追加、`contains()` で存在確認、`remove()` で削除
• 配列やリストから HashSet を作ることで重複削除ができる
Set とは
Set(セット、集合)は「重複を許さない要素の集まり」です。数学の「集合」と同じ概念です。
| 用語 | 説明 |
|---|---|
| Set | インターフェース(契約)。重複不可のコレクション |
| HashSet | Set を実装した代表的なクラス。順序なし |
| LinkedHashSet | 挿入順を保持する Set |
| TreeSet | 自動的にソートされる Set(要素が Comparable) |
ポイント: 同じ要素を複数回 `add()` しても、実際には1つしか保存されません。これが Set の最大の特徴です。
List と Set の違い
| 項目 | List(例: ArrayList) | Set(例: HashSet) |
|---|---|---|
| 重複 | 許可(同じ値を複数持てる) | 不可(自動排除) |
| 順序 | あり(インデックス順) | なし(HashSet の場合) |
| アクセス | get(index) で取得可 | インデックスアクセス不可 |
| 主な用途 | 学生リスト、タスクリスト | ユニーク要素の管理、重複削除 |
HashSet の基本的な使い方
1. import
import java.util.HashSet;
import java.util.Set;
2. HashSet の宣言と生成
// Java 21
Set<String> uniqueNames = new HashSet<>();
3. 要素を追加する(add)
uniqueNames.add("Alice");
uniqueNames.add("Bob");
uniqueNames.add("Alice"); // 重複。実際には追加されない
System.out.println(uniqueNames.size()); // 2(Alice は1つだけ)
add() の戻り値は boolean で、追加に成功したら true、既に存在していたら false です。
boolean added1 = uniqueNames.add("Charlie"); // true
boolean added2 = uniqueNames.add("Charlie"); // false(既に存在)
4. 要素が存在するか確認(contains)
if (uniqueNames.contains("Alice")) {
System.out.println("Alice は登録済み");
}
5. 要素を削除する(remove)
uniqueNames.remove("Bob"); // Bob を削除
6. 要素数を確認(size)
int count = uniqueNames.size();
7. 全削除(clear)
uniqueNames.clear();
HashSet の主要メソッド
| メソッド | 説明 | 戻り値 |
|---|---|---|
add(E element) | 要素を追加(重複なら追加しない) | boolean(追加成功なら true) |
contains(Object o) | 要素が存在するか | boolean |
remove(Object o) | 要素を削除 | boolean(削除成功なら true) |
size() | 要素数 | int |
isEmpty() | 空かどうか | boolean |
clear() | 全削除 | void |
注意: HashSet は**順序を保証しません**。for 文で走査する際、追加順と異なる順序で出てくることがあります。
実践例: 重複削除
配列やリストから重複を取り除きたい場合、HashSet に変換するのが定石です。
// Java 21
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] fruits = {"Apple", "Banana", "Apple", "Orange", "Banana", "Apple"};
// 配列 → HashSet で重複削除
Set<String> uniqueFruits = new HashSet<>(Arrays.asList(fruits));
System.out.println("ユニークな果物:");
for (String fruit : uniqueFruits) {
System.out.println(fruit);
}
System.out.println("\n元の配列の長さ: " + fruits.length); // 6
System.out.println("重複削除後: " + uniqueFruits.size()); // 3
}
}
出力(順序は不定):
ユニークな果物:
Apple
Banana
Orange
元の配列の長さ: 6
重複削除後: 3
ポイント: `new HashSet<>(Arrays.asList(配列))` で、配列を Set に変換できます。これだけで重複が自動排除されます。
List vs Set(使い分けの例)
| 状況 | 推奨 | 理由 |
|---|---|---|
| 学生の出席リスト | List | 同じ人が複数回記録される場合あり |
| ログインユーザーID(オンライン中) | Set | 重複を許さない |
| 購買履歴(時系列) | List | 順序と重複が重要 |
| タグ(ブログ記事など) | Set | 同じタグを2回登録しない |
| アクセスしたページURL(履歴) | List | 順序が大事 |
| 訪問済みURL(重複チェック) | Set | 訪問済みかどうかだけ知りたい |
拡張 for 文で走査
HashSet は順序がありませんが、全要素を走査できます。
// Java 21
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.add(20); // 重複、追加されない
System.out.println("Set の要素:");
for (int num : numbers) {
System.out.println(num);
}
}
}
出力(順序は不定):
Set の要素:
10
20
30
不変セット(Set.of)
不変セットは、一度作ったら変更不可です。Java 9 以降、Set.of() で作成できます。
// Java 21
import java.util.Set;
Set<String> colors = Set.of("Red", "Green", "Blue");
System.out.println(colors.contains("Red")); // true
System.out.println(colors.size()); // 3
// 変更しようとするとエラー
// colors.add("Yellow"); // UnsupportedOperationException
| 特徴 | 説明 |
|---|---|
| 不変 | add / remove が使えない |
| 簡潔 | 要素を並べるだけ |
| 重複禁止 | Set.of("A", "A") は IllegalArgumentException |
| null 禁止 | Set.of(null) は NullPointerException |
注意: `Set.of()` は重複を許しません。重複があると実行時エラーになります。
実践例: ユニーク要素の抽出
ユーザー入力から重複を排除して一覧を作成します。
// Java 21
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
String input = "apple,banana,apple,orange,banana,grape,apple";
String[] items = input.split(",");
Set<String> uniqueItems = new HashSet<>();
for (String item : items) {
if (uniqueItems.add(item)) {
System.out.println("新規追加: " + item);
} else {
System.out.println("重複検出: " + item);
}
}
System.out.println("\nユニーク項目:");
uniqueItems.forEach(System.out::println);
}
}
出力:
新規追加: apple
新規追加: banana
重複検出: apple
新規追加: orange
重複検出: banana
新規追加: grape
重複検出: apple
ユニーク項目:
apple
banana
orange
grape
補足: `add()` の戻り値(boolean)を活用すると、追加と重複検出を同時に行えます。
HashSet の内部動作(補足)
HashSet は内部で HashMap を使っています。要素を「キー」として格納し、値はダミーオブジェクトです。
| 操作 | 計算量(平均) | 備考 |
|---|---|---|
add(E) | O(1) | ハッシュ衝突が少ない場合 |
contains(E) | O(1) | 同上 |
remove(E) | O(1) | 同上 |
ポイント: HashSet は検索(contains)が超高速(O(1))です。ArrayList の `contains()` は O(n) なので、大量の要素から「存在チェック」を繰り返すなら HashSet が圧倒的に速いです。
List / Set / Map の総まとめ
これまで学んだ3大コレクションの比較です。
| 種類 | 代表クラス | 重複 | 順序 | 主なメソッド | 用途 |
|---|---|---|---|---|---|
| List | ArrayList | 可 | あり | add / get / set / remove | 学生リスト、履歴 |
| Set | HashSet | 不可 | なし | add / contains / remove | タグ、ユニークID |
| Map | HashMap | キー不可、値可 | なし | put / get / containsKey | 辞書、設定、カウント |
ポイント: 「重複を許すか」「順序が必要か」「名前で引くか」で使い分けます。迷ったら、重複NGならSet、名前引きならMap、それ以外はListです。
まとめ
| 概念 | 説明 |
|---|---|
| Set | 重複を許さないコレクションのインターフェース |
| HashSet | ハッシュテーブルベースの実装。高速(O(1)) |
| add / contains / remove | 基本操作。add は重複時に false を返す |
| 重複削除 | 配列やリストから HashSet を作成するだけで実現 |
| 順序 | HashSet は順序なし。LinkedHashSet で挿入順を保持 |
| Set.of() | 不変セットを簡潔に作成(Java 9以降) |
次のステップ(発展学習へ)
おめでとうございます! Java入門シリーズのコレクション編(List / Map / Set)が完了しました。これで基本的なデータ構造の選択ができるようになりました。
さらに学ぶべきこと
| 分野 | 学習内容 | 理由 |
|---|---|---|
| 例外処理 | try-catch-finally, throws | エラーハンドリングの基本 |
| ファイル入出力 | Files, BufferedReader, Path | データの永続化 |
| 継承とインターフェース | extends, implements, 抽象クラス | オブジェクト指向設計 |
| ラムダ式とStream API | stream(), filter(), map() | 関数型プログラミング |
| ジェネリクス応用 | 独自ジェネリッククラスの作成 | 型安全な設計 |
本サイトに今後、例外処理やファイル入出力の入門記事が追加される予定です。
補足: コレクションを使いこなせるようになったら、Stream API(Java 8以降)を学ぶと、データ処理が劇的に簡潔になります。`list.stream().filter(...).map(...).collect(...)` のような記法です。
参考リソース
- Oracle HashSet API ドキュメント — HashSet 公式リファレンス
- Oracle Set API — Set インターフェース
- Java Collections Framework — 公式チュートリアル
- Effective Java (Joshua Bloch) — equals / hashCode のベストプラクティス