はじめに
Javaで複数の値を順序付きで扱うなら、中心になる型はListです。ArrayList、LinkedList、List.of、Arrays.asListの違いを押さえると、追加、取得、削除、並び替え、変換、例外対策まで見通しよく整理できます。
その理解が曖昧なままだと、IndexOutOfBoundsException、UnsupportedOperationException、意図しない参照共有、スレッド間の不整合でつまずきやすくなります。そのため、最小コードで動作の形を確認しながら、用途ごとに選ぶ実装を決めるのが現実的でしょう。
- Java 21 / OpenJDK 21
- 標準ライブラリ: java.util パッケージ
List、ArrayList、LinkedListの使い分けadd、get、set、removeの基本操作Iterator、ラムダ式、Stream APIによる走査と加工- 配列、
Set、コピー、比較への変換パターン - 範囲外アクセス、変更不可リスト、同期化の注意点
公式ドキュメントによれば、Java SE 21のListは順序を持つコレクションで、要素は整数インデックスで扱えます。Java SE 21のArrayListも、基本動作を確認する一次情報として参照できます。
Javaとは
Javaは、JVM上で動くオブジェクト指向言語です。コンパイルされた.classファイルは仮想マシンで実行されるため、サーバーアプリケーション、Android、業務システムなどで広く利用されますし、ここがポイントです。
その特徴は、classを中心にデータと処理をまとめ、packageで名前空間を分け、publicやprivateでアクセス範囲を制御できる点です。一方、型が明確な言語なので、List<String>のようなジェネリクスを使うと、文字列だけを入れるリストとして扱えます。
基本的にJavaのコレクションはjava.utilにまとまっています。Collection、List、Set、Mapを軸に考えると、順序、重複、キー検索という違いを整理しやすいです。
Javaの基礎文法を補強したい場合は、Javaのオブジェクト指向ガイドも役立ちますが、これは押さえたい点です。Listはオブジェクト指向の考え方と組み合わせて使う場面が多いため、interfaceと実装クラスの関係も合わせて見ると理解が進みますし、ここがポイントです。
List型とは
Listは順序を保持し、同じ値の重複も許すコレクションです。配列のString[]は長さが固定されますが、ArrayListは要素数に応じて内部配列を広げられます。
そのため、ユーザー入力、検索結果、CSVの行、APIレスポンスの一覧など、件数が実行時まで決まらないデータに向いているのが基本です。ただし、実装クラスによって得意な操作が変わるため、名前だけで選ばず処理内容から判断するとよい。
| 項目 | 主なAPI | 用途 | 注意点 |
|---|---|---|---|
| 生成 | new ArrayList<>() | 変更できるリスト | 型引数を合わせる |
| 生成 | new LinkedList<>() | 先頭付近の追加削除 | ランダムアクセスは遅くなりやすい |
| 生成 | List.of | 変更しない定数リスト | null不可 |
| 追加 | add | 末尾または指定位置へ追加 | 位置指定は既存要素が後ろへずれる |
| 取得 | get | インデックスで読む | 範囲外で例外 |
| 変更 | set | 既存要素の置換 | 追加ではない |
| 削除 | remove | 位置または値で削除 | Integerはオーバーロードに注意 |
| 件数 | size | ループ範囲の判断 | 最後のインデックスはsize() - 1 |
| 空判定 | isEmpty | 要素がないか確認 | null参照とは別 |
| 検索 | contains | 値の有無を確認 | 内部的にequalsが使われる |
| 位置検索 | indexOf | 最初の位置を取得 | 見つからない場合は-1 |
| 末尾検索 | lastIndexOf | 後ろ側の位置を取得 | 重複値で使う |
| 範囲 | subList | 一部のビューを扱う | 元リスト変更の影響に注意 |
| 走査 | for | 添字付き処理 | LinkedListでは非効率な場合 |
| 走査 | for-each | 全要素の読み取り | 添字不要の処理向き |
| 走査 | Iterator | 安全な順次処理 | 削除はiterator.removeを検討 |
| 加工 | replaceAll | 全要素を置換 | 変更可能リストで使う |
| 並び替え | sort | 自然順や条件順に整列 | Comparatorを渡せる |
| 変換 | stream | 抽出や集計 | 終端操作が必要 |
| 収集 | collect | 結果をリスト化 | Java 16以降はtoListも候補 |
| 配列化 | toArray | 配列APIへ渡す | 型付き配列を渡す |
| 配列から | Arrays.asList | 配列をリスト表示 | サイズ変更不可 |
| コピー | new ArrayList<>(list) | 変更可能コピー | 浅いコピー |
| 変更不可 | List.copyOf | 防御的コピー | 要素オブジェクト自体は別問題 |
| 重複排除 | new HashSet<> | 一意化 | 順序が必要ならLinkedHashSet |
| 同期化 | Collections.synchronizedList | 単純な同期 | 複合操作は同期ブロックを検討 |
| 例外 | IndexOutOfBoundsException | 範囲外アクセス | 事前にsizeで確認 |
| 例外 | UnsupportedOperationException | 変更不可リスト変更 | 生成方法を確認 |
| 比較 | equals | 順序と要素の一致 | 同じ要素でも順序違いは不一致 |
| 削除条件 | removeIf | 条件一致を削除 | 述語の副作用を避ける |
具体的には、ArrayListは末尾追加と添字アクセスを多用する一覧に向きます。一方、LinkedListは構造上ノードをたどるため、単純なgetの多用には向かないと考えられる。
結果: 期待される出力は「りんご」です。get(0)は先頭要素を取得します。
結果: 期待される出力は10、20、30の順です。for-eachはリストの順序を保って走査します。
💡 Tips:Listはインターフェースなので、変数の型はList<String>、生成はnew ArrayList<>()のように書くと、実装の差し替え余地を残せます。
Java List型の基本操作
Java List型の基本操作は、生成、追加、取得、変更、削除に分けると整理しやすいです。初心者がつまずきやすいのは、インデックスが0から始まる点と、remove(1)とremove(Integer.valueOf(1))の意味が変わる点になるのが目安です。
その違いを理解するには、短いコードでsizeと中身を出すのが近道です。Javaの制御構文やクラスの考え方に不安があれば、Javaのオーバーライド解説でメソッドの振る舞いも確認できます。
Listインスタンスの生成
結果: 期待される出力は「0」です。ArrayListは生成直後なら空のリストになります。
結果: 期待される出力は「true」です。LinkedListもListとして扱えます。
要素の追加と取得
要素を増やす処理ではadd、読む処理ではgetを使いるのがポイントです。このとき、add(value)は末尾追加、add(index, value)は指定位置への挿入という違いがあるのが基本です。
結果: 期待される出力は「りんご」「ばなな」「みかん」の順です。addした順序が保持されます。
結果: 期待される出力は「2番目のフルーツは: ばなな」です。get(1)は人間の数え方では2番目にあたります。
結果: 期待される出力は「[A, B, C]」です。add(1, "B")により、既存のCは後ろへ移動します。
要素の削除と変更
要素を取り除くときはremove、置き換えるときはsetを使います。ただし、setは既存位置の更新なので、空の位置へ値を入れる用途には使えません。
結果: 期待される出力は「[りんご, ばなな]」です。remove(1)によりインデックス1の要素が削除されます。
結果: 期待される出力は「[りんご, グレープフルーツ, ばなな]」です。setは要素数を変えずに値だけを置き換えます。
結果: 期待される出力は「[1, 3]」です。Integer.valueOf(2)を渡すと、インデックスではなく値の2を削除します。
List<Integer>でremove(2)と書くと、値の2ではなくインデックス2の削除として解釈されます。値を消すならInteger.valueOfを使うと明確です。サンプルコードとその解説
サンプルコードでは、基本操作からラムダ式、Stream、並び替え、配列変換、コピー、比較までをつなげて確認するのが一般的です。実装パターンとしてよく見るのは、Listで受け取り、必要に応じてArrayListへコピーしてから変更する形です。
これらの処理はWebアプリケーションの一覧表示や入力値の整形でもよく使われますが、これは押さえたい点です。注釈や設定値の扱いを合わせて学ぶなら、Javaアノテーションのガイドも関連します。
サンプルコード1:Listの基本操作
結果: 期待される出力は「取得した要素: Banana」、続いて「[Apple, Orange, Banana, Cherry]」、削除後に「[Apple, Orange, Cherry]」です。
サンプルコード2:Iteratorを利用した操作
結果: 期待される出力は「リンゴ」「バナナ」「オレンジ」の順です。hasNextで次の要素を確認し、nextで値を取り出します。
結果: 期待される出力は「[A, C]」です。走査中の削除ではIterator.removeを使うと意図が明確になります。
サンプルコード3:ラムダ式を利用した操作
結果: 期待される出力は「APPLE」「BANANA」「CHERRY」です。replaceAllが各要素を大文字へ置き換えます。
結果: 期待される出力は「[1, 3]」です。removeIfに渡した条件に合う偶数が取り除かれます。
サンプルコード4:Stream APIを利用した操作
Stream APIは、リストを直接変更せずに変換や抽出を表現しやすい書き方です。一方、読みやすさは処理の長さに左右されるため、単純な全件表示ならfor-eachのほうが扱いやすい場合もあります。
結果: 期待される出力は「[1, 2, 3, 4, 5]」です。List.ofは変更不可のリストを作りますし、これが一つの目安です。
結果: 期待される出力は「[2, 4, 6, 8, 10]」です。mapは各要素を変換します。
結果: 期待される出力は「[2, 4, 6]」です。filterは条件に合う要素だけを残します。
結果: 期待される出力は「15」です。reduceは要素を畳み込んで単一の値にします。
サンプルコード5:Listの並び替え
結果: 期待される出力は「[Apple, Banana, Cherry]」です。Collections.sortは自然順で並び替えます。
結果: 期待される出力は「[Cherry, Banana, Apple]」です。Comparator.reverseOrderにより降順になります。
サンプルコード6:Listと配列の相互変換
結果: 期待される出力は「りんご」「ばなな」「みかん」の順です。toArray(new String[0])で型付き配列へ変換できます。
結果: 期待される出力は「[りんご, ばなな, みかん]」です。Arrays.asListで配列をリストとして扱えます。
サンプルコード7:Listのコピーと比較
結果: 期待される出力は元のリストが「[Apple, Banana, Cherry]」、コピー側が「[Apple, Banana, Cherry, Date]」です。
結果: 期待される出力は「true」です。equalsは要素と順序が一致する場合にtrueを返します。
Java List型の応用
Java List型の応用では、部分リスト、重複排除、変更不可リスト、条件削除などを組み合わせます。一般的に、読み取り用のリストと更新用のリストを分けると、予期しない変更を抑えやすいです。
その考え方は、日付判定や入力チェックのような処理にも通じますが、覚えておくと役立つでしょう。条件分岐の書き方を補いたい場合は、Javaでうるう年を判定する解説が参考になるのが目安です。
結果: 期待される出力は「[ぶどう, みかん]」です。subList(2, 4)は開始位置を含み、終了位置を含みません。
結果: 期待される出力は重複しない果物名の集合です。HashSetは順序を保証しないため、表示順は固定と考えないほうがよい。
結果: 期待される出力は「[A, B, C]」です。LinkedHashSetを使うと、初出順を保ちながら重複を排除できます。
結果: 期待される出力は「true」です。List.copyOfは変更不可リストを作る用途に向きます。
List.ofやList.copyOfで作ったリストにaddやsetを行うと、UnsupportedOperationExceptionが発生するのが現実的です。更新する予定があるならnew ArrayList<>(source)で変更可能なコピーを作りますし、これが一つの目安です。注意点と対処法
注意点として特に押さえたいのは、範囲外アクセス、変更不可リスト、マルチスレッドでの共有です。これらはコンパイル時に見つからない場合があり、実行時例外として表面化します。
そのため、sizeで範囲を確認し、変更可能性を生成時に決め、共有リストの複合操作では同期を検討すると整理できます。文字列の扱いも合わせて整理するなら、Javaエスケープ処理の解説も確認するとよいでしょう。
結果: 期待される出力は「1」「2」の順です。Collections.synchronizedListを使っても、反復処理では同期ブロックを組み合わせるのが一般的です。
結果: 期待される出力は1から5までの数値と、末尾に「インデックスが範囲外です」です。i < list.size()で範囲外アクセスを避けます。
結果: 期待される出力は「2」です。このリストは読み取りには使えますが、addなどの変更操作には向きません。
結果: 期待される出力は「true」です。ArrayListはnullを保持できますが、List.ofではnullを受け付けません。
subListは独立した完全コピーではなく、元リストと関係を持つビューです。安全に保存したい場合はnew ArrayList<>(list.subList(...))でコピーします。まとめ
JavaのListは、順序付きの複数データを扱うための中心的なインターフェースです。変更可能な一覧にはArrayList、先頭や末尾の操作を意識する場面ではLinkedList、変更させたくない定数的な一覧にはList.ofやList.copyOfを使い分けます。
基本操作はadd、get、set、remove、sizeに集約できると理解できるのがポイントです。その上で、Iterator、forEach、stream、filter、map、collectを覚えると、読み取り、変換、抽出のコードが組み立てやすくなります。
ただし、インデックスは0始まりであり、範囲外ならIndexOutOfBoundsExceptionになります。変更不可リストに更新操作を行えばUnsupportedOperationExceptionが発生するため、生成方法と用途を合わせることが安定した実装につながる。
関連記事
- Javaアノテーションの12選!初心者から上級者まで徹底ガイド
- Javaでうるう年を判定!初心者でも分かる9ステップ解説
- Javaエスケープ処理の10ステップマスターガイド
- Javaでマスターする!オーバーライドのたった7つのステップ
- オブジェクト指向を10ステップで完全マスター
※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。


