6.

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<String> 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<String> immut = List.of("a", "b", "c");
// immut.add("d");  // UnsupportedOperationException

// 既存リストから不変リスト
List<String> 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<Integer> set = new HashSet<>();
set.add(1); set.add(2); set.add(1);  // 重複は無視
set.size();                           // 2

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

// TreeSet で範囲検索
NavigableSet<Integer> 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<String> 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<Integer> stack = new ArrayDeque<>();
stack.push(1); stack.push(2); stack.push(3);
stack.pop();   // 3
stack.peek();  // 2

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

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

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

Map の使い分け

実装get/put順序備考
HashMapO(1) 平均なし★ 通常はこれ。null キー/値 OK
LinkedHashMapO(1)挿入順 or アクセス順LRU キャッシュにも使える
TreeMapO(log n)キーソート範囲検索可
ConcurrentHashMapO(1) 平均なし★ スレッドセーフ。マルチスレッド推奨
HashtableO(1)なし古い。同期だが性能悪い。使わない
Map<String, Integer> 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<String, Integer> count = new HashMap<>();
for (String word : words) {
    count.merge(word, 1, Integer::sum);
}

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

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

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

Stream API (Java 8+)

import java.util.stream.*;

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

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

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

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

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

スレッドセーフ化

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

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

// 3. ブロッキングキュー (プロデューサ/コンシューマ)
BlockingQueue<Task> 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)

編集
Post Share
子ページ
  1. List
同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ