1.

Java ArrayList完全ガイド(容量/API/List.of/スレッドセーフ/性能)

編集
この記事の要点
  • ArrayList = 内部配列を使った可変長 List 実装。Java で最も使われるコレクション
  • 生成は new ArrayList<>()初期容量を渡せば再アロケーション削減: new ArrayList<>(1000)
  • 主要 API: add / get / set / remove / contains / size / indexOf / subList
  • Arrays.asList固定長のリスト、List.of不変。混同注意
  • 内部は resize 倍々(1.5 倍)。末尾追加は償却 O(1)、中間挿入は O(n)
  • スレッドセーフが必要なら CopyOnWriteArrayList(読み多書き少)、Collections.synchronizedList、または並行アクセスを避ける設計
  • 巨大データでランダムアクセスなら ArrayList、頻繁な先頭挿入なら ArrayDeque / LinkedList を検討

ArrayList とは

java.util.ArrayList は内部に配列を持つ可変長 List 実装です。インデックスアクセスは O(1)、末尾への追加は償却 O(1)、中間挿入/削除は O(n)。Java で最も多用されるコレクションです。

生成と初期化

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

// 空の ArrayList
List<String> a1 = new ArrayList<>();

// 初期容量指定(大量追加が分かっているとき必須)
List<String> a2 = new ArrayList<>(1000);

// 既存コレクションから
List<String> a3 = new ArrayList<>(Arrays.asList("a", "b", "c"));
List<String> a4 = new ArrayList<>(List.of("a", "b", "c"));

// 配列から
String[] arr = {"x", "y", "z"};
List<String> a5 = new ArrayList<>(Arrays.asList(arr));

主要メソッド一覧

API計算量説明
add(e)償却 O(1)末尾追加
add(i, e)O(n)位置 i に挿入(以降ずらす)
get(i)O(1)位置 i 取得
set(i, e)O(1)位置 i を上書き
remove(i)O(n)位置 i 削除(以降詰める)
remove(Object)O(n)最初に一致する要素削除
contains(e)O(n)線形探索
indexOf(e)O(n)線形探索
size()O(1)要素数
isEmpty()O(1)空か
clear()O(n)全削除(参照を null に)
subList(from, to)O(1)ビュー(元と連動)
toArray()O(n)配列化
List<String> list = new ArrayList<>();
list.add("Alice");
list.add("Bob");
list.add(0, "Header");    // 先頭に挿入: [Header, Alice, Bob]

String x = list.get(1);   // Alice
list.set(1, "Anna");      // [Header, Anna, Bob]
list.remove("Bob");       // [Header, Anna]

boolean hasA = list.contains("Anna");  // true
int idx = list.indexOf("Header");      // 0

list.forEach(System.out::println);
list.removeIf(s -> s.startsWith("H")); // [Anna]

List.of / Arrays.asList / new ArrayList の違い

サイズ要素変更null 許容用途
List.of("a","b")固定不可(UnsupportedOperationException)不可★ 不変リスト
Arrays.asList("a","b")固定長可(set のみ)配列のリストビュー
new ArrayList<>(List.of(...))可変★ 通常用途
// ❌ Arrays.asList の add でエラー
List<String> a = Arrays.asList("a", "b");
a.add("c");  // UnsupportedOperationException

// ❌ List.of の set でエラー
List<String> b = List.of("a", "b");
b.set(0, "x");  // UnsupportedOperationException

// ✅ 変更したいなら ArrayList でラップ
List<String> c = new ArrayList<>(List.of("a", "b"));
c.add("c");  // OK

不変化と Read-Only ビュー

List<String> mutable = new ArrayList<>(List.of("a", "b"));

// Read-only ビュー(元を変えるとビューも変わる)
List<String> ro = Collections.unmodifiableList(mutable);
ro.add("c");      // UnsupportedOperationException
mutable.add("c"); // OK → ro でも "c" が見える

// 完全コピーして不変化
List<String> immutable = List.copyOf(mutable);
mutable.add("d");
// → immutable は変わらない

内部実装と容量

内部に Object[] を持ち、容量が足りなくなったら1.5 倍に拡張します(newCapacity = oldCapacity + (oldCapacity >> 1))。デフォルト初期容量は 10。

// ❌ 100 万要素を追加するなら容量を最初に確保
List<Integer> bad = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) bad.add(i);
// → 内部で何回もリサイズ・コピー発生

// ✅ 容量指定で高速化
List<Integer> good = new ArrayList<>(1_000_000);
for (int i = 0; i < 1_000_000; i++) good.add(i);

// trimToSize() で余剰容量を解放
((ArrayList<Integer>) good).trimToSize();

スレッドセーフ

ArrayList はスレッドセーフではありません。複数スレッドから書き込むと ConcurrentModificationException や ArrayIndexOutOfBoundsException が発生します。

// 選択肢1: Collections.synchronizedList
List<String> s = Collections.synchronizedList(new ArrayList<>());
synchronized (s) {                        // iterate は要外部同期
    for (String x : s) System.out.println(x);
}

// 選択肢2: CopyOnWriteArrayList(読み多書き少)
List<String> cow = new CopyOnWriteArrayList<>();
// 書き込みごとに配列を丸ごとコピー → 重いが iterate は安全

// 選択肢3: スレッドごとに別リスト → 最後に集約(推奨)
List<List<String>> partial = ...;  // 各スレッド独立
List<String> merged = partial.stream()
    .flatMap(List::stream)
    .toList();

性能ヒント

  • 大量の末尾追加 → ArrayList(初期容量指定)
  • 大量の先頭/中間挿入 → ArrayDequeLinkedList
  • 頻繁な contains 検索 → HashSet を併用
  • iterate 中の削除 → Iterator.remove() または removeIf
  • 巨大データのメモリ削減 → プリミティブ特化型 (Eclipse Collections, fastutil)

FAQ

Q: list.remove(1) はインデックス削除?要素削除?
A: List<Integer> だとインデックス削除が優先されます。要素 1 を消したいなら list.remove(Integer.valueOf(1))

Q: subList は新しいリスト?
A: ビューです。元を変更するとビューに反映されます。独立したコピーがほしければ new ArrayList<>(list.subList(0, 10))

Q: ArrayList と Vector の違いは?
A: Vector は古いスレッドセーフ実装。現在では synchronizedListCopyOnWriteArrayList に置き換えるべきです。

編集
Post Share
子ページ
  1. 要素の数を数える
同階層のページ

同階層のページはありません

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