この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:8
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: コレクション(List,Set,Queue)
SEOタイトル: Java コレクション (List/Set/Queue/Map) 完全ガイド - 計算量と使い分け

この記事の要点
  • Java Collection Framework は List / Set / Queue / Map の 4 系統。すべて java.util
  • List: 順序あり・重複あり (ArrayList / LinkedList / Vector)
  • Set: 重複なし (HashSet / TreeSet / LinkedHashSet)
  • Queue/Deque: FIFO/LIFO (ArrayDeque / LinkedList / PriorityQueue)
  • Map: キー→値 (HashMap / TreeMap / LinkedHashMap / ConcurrentHashMap)

Java Collection Framework 全体図

Iterable
└── Collection
    ├── List          (順序あり・重複OK)
    │   ├── ArrayList     ★ 主力
    │   ├── LinkedList    (Queue/Deque も実装)
    │   └── Vector        (スレッドセーフ、古い)
    │
    ├── Set           (重複NG)
    │   ├── HashSet       ★ 主力
    │   ├── LinkedHashSet (挿入順保持)
    │   └── TreeSet       (ソート済 - SortedSet)
    │
    └── Queue / Deque (FIFO/LIFO)
        ├── ArrayDeque    ★ 主力 (Stack/Queue)
        ├── LinkedList
        └── PriorityQueue (優先度キュー)

Map (Collection ではない別系統)
├── HashMap            ★ 主力
├── LinkedHashMap      (挿入順保持)
├── TreeMap            (ソート済)
├── Hashtable          (古い・非推奨)
└── ConcurrentHashMap  (スレッドセーフ)

List の使い分け

実装get(i)add 末尾add(0)remove(0)備考
ArrayListO(1)O(1) ※O(n)O(n)★ 通常はこれ。内部は配列
LinkedListO(n)O(1)O(1)O(1)双方向連結。両端操作多用なら
VectorO(1)O(1) ※O(n)O(n)古い・同期版。代わりに Collections.synchronizedList

※ ArrayList の末尾追加は均し O(1) (配列拡張時のみ O(n))。

import java.util.*;

List list = new ArrayList<>();
list.add("A");
list.add("B");
list.add(0, "Z");        // 先頭挿入 (遅い)
list.get(0);             // "Z"
list.remove("A");
list.size();
list.contains("B");

// 不変リスト (Java 9+)
List immut = List.of("a", "b", "c");
// immut.add("d");  // UnsupportedOperationException

// 既存リストから不変リスト
List copy = List.copyOf(list);

// for-each (Iterable)
for (String s : list) {
    System.out.println(s);
}

// ソート
Collections.sort(list);                   // 自然順序
list.sort(Comparator.reverseOrder());     // 逆順
list.sort(Comparator.comparing(String::length));

Set の使い分け

実装add/contains順序備考
HashSetO(1) 平均なし★ 通常はこれ
LinkedHashSetO(1) 平均挿入順イテレート順を保ちたいとき
TreeSetO(log n)ソート済範囲検索 (subSet 等) や first() が必要なとき
Set set = new HashSet<>();
set.add(1); set.add(2); set.add(1);  // 重複は無視
set.size();                           // 2

// 重複排除に便利
List raw = List.of(1, 2, 2, 3, 3, 3);
Set unique = new HashSet<>(raw);  // [1, 2, 3]

// TreeSet で範囲検索
NavigableSet tree = new TreeSet<>(List.of(1, 3, 5, 7, 9));
tree.first();           // 1
tree.last();            // 9
tree.higher(4);         // 5 (4 より大きい最小)
tree.subSet(3, 8);      // [3, 5, 7]

// 不変 Set (Java 9+)
Set immut = Set.of("a", "b", "c");

Queue / Deque の使い分け

実装用途備考
ArrayDequeStack / Queue / Deque★ Stack の代替推奨。null 不可
LinkedListQueue / DequeList も兼ねるが性能は ArrayDeque に劣る
PriorityQueue優先度付きキューヒープ。poll() で最小値取得
LinkedBlockingQueue並行プログラミングjava.util.concurrent
// Stack (LIFO) - 古い Stack クラスより ArrayDeque 推奨
Deque stack = new ArrayDeque<>();
stack.push(1); stack.push(2); stack.push(3);
stack.pop();   // 3
stack.peek();  // 2

// Queue (FIFO)
Queue queue = new ArrayDeque<>();
queue.offer("A");
queue.offer("B");
queue.poll();  // "A"

// 優先度キュー (小さい順)
PriorityQueue pq = new PriorityQueue<>();
pq.offer(5); pq.offer(1); pq.offer(3);
pq.poll();   // 1
pq.poll();   // 3

// 大きい順
PriorityQueue pqDesc = new PriorityQueue<>(Comparator.reverseOrder());

Map の使い分け

実装get/put順序備考
HashMapO(1) 平均なし★ 通常はこれ。null キー/値 OK
LinkedHashMapO(1)挿入順 or アクセス順LRU キャッシュにも使える
TreeMapO(log n)キーソート範囲検索可
ConcurrentHashMapO(1) 平均なし★ スレッドセーフ。マルチスレッド推奨
HashtableO(1)なし古い。同期だが性能悪い。使わない
Map map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.get("a");                         // 1
map.getOrDefault("z", 0);             // 0
map.containsKey("a");                 // true
map.putIfAbsent("c", 3);              // 既存なら無視

// 集計イディオム
Map count = new HashMap<>();
for (String word : words) {
    count.merge(word, 1, Integer::sum);
}

// イテレート
for (Map.Entry e : map.entrySet()) {
    System.out.println(e.getKey() + " = " + e.getValue());
}

// 不変 Map (Java 9+)
Map immut = Map.of("a", 1, "b", 2);
Map big = Map.ofEntries(
    Map.entry("a", 1),
    Map.entry("b", 2)
);

// LRU キャッシュ
Map lru = new LinkedHashMap<>(16, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > 100;
    }
};

Stream API (Java 8+)

import java.util.stream.*;

List nums = List.of(1, 2, 3, 4, 5);

// フィルタ + マップ + 集計
int sum = nums.stream()
    .filter(n -> n % 2 == 0)
    .mapToInt(Integer::intValue)
    .sum();   // 6

// グルーピング
Map> grouped = nums.stream()
    .collect(Collectors.partitioningBy(n -> n % 2 == 0));

// List → Map
Map userMap = users.stream()
    .collect(Collectors.toMap(User::getId, u -> u));

// 並列ストリーム
nums.parallelStream().forEach(System.out::println);

スレッドセーフ化

// 1. 古い同期ラッパ (性能低い・推奨されない)
List syncList = Collections.synchronizedList(new ArrayList<>());
Map syncMap = Collections.synchronizedMap(new HashMap<>());

// 2. ★ 推奨: java.util.concurrent
import java.util.concurrent.*;
ConcurrentHashMap cmap = new ConcurrentHashMap<>();
CopyOnWriteArrayList cowList = new CopyOnWriteArrayList<>();
ConcurrentLinkedQueue cqueue = new ConcurrentLinkedQueue<>();

// 3. ブロッキングキュー (プロデューサ/コンシューマ)
BlockingQueue queue = new LinkedBlockingQueue<>();
queue.put(task);          // 満杯ならブロック
Task t = queue.take();    // 空ならブロック

選び方フローチャート

  • キーで値を引きたいHashMap。順序が必要なら LinkedHashMap or TreeMap。並行なら ConcurrentHashMap
  • 重複を排除したいHashSet。順序保持なら LinkedHashSet。ソートなら TreeSet
  • 順序ある可変リストArrayList。先頭挿入頻発なら LinkedList
  • Stack / QueueArrayDeque (Stack クラスや LinkedList より速い)
  • 優先度順に取り出すPriorityQueue
  • 読み取り専用List.of / Set.of / Map.of (Java 9+)

FAQ

Q: HashMap で順序を保ちたい
A: LinkedHashMap を使ってください。HashMap はハッシュ値順なので順序保証ゼロです。

Q: HashSet が遅い。なぜ?
A: 格納する要素の hashCode() / equals() 実装が悪いと衝突が増えて O(n) に劣化します。Java 8+ は衝突過多時に内部を木構造化しますが、根本は hashCode を直すこと。

Q: List → 配列に変換したい
A: String[] arr = list.toArray(new String[0]);。Java 11+ は list.toArray(String[]::new)