【Java】Listの使い方完全ガイド|ArrayList宣言・add/get/set/remove・配列との違い

リストの使い方_アイキャッチ画像 Java

Listとは?配列との違いをまず理解しよう

「Listと配列の違いが分からない!」「Listってどうやって使うの?」という方のために、JavaのListの使い方を基礎から解説します。

今回は特によく使われる実装クラスであるArrayListを中心に、宣言方法から追加・取得・削除・ソートといった実務で頻出する操作まで、実行結果付きのサンプルコードでまとめて紹介します。

GeeksforGeeksの解説によると、Listはjava.util.Collectionを継承したインターフェースで、次のような特徴を持ちます。

  • 挿入した順序を保持する
  • 重複した要素を許可する
  • インデックス(添字)を指定して要素にアクセスできる

配列とよく似ていますが、Listは配列よりも汎用性が高く、特に「要素数を自由に増減できる」点が大きな違いです。

配列について詳しく知りたい方は、先にこちらの記事を読んでおくとスムーズに理解できます。

【Java】配列の使い方【初心者向け】

配列とListの違い一覧

比較項目 配列(Array) List(ArrayList)
要素数の変更 宣言後は不可(固定) 自由に追加・削除できる
格納できる型 プリミティブ型もOK(int[]など) プリミティブ型は不可。ラッパークラス(Integerなど)が必要
用意されているメソッド ほとんどない add/get/set/removeなど豊富
パフォーマンス 高速 配列よりわずかに遅い(内部で配列をラップしているため)
用途 要素数が固定で分かっている場合 要素数が変動する場合・柔軟な操作をしたい場合

このように、「配列は要素数固定・Listは可変」という点が最大の違いです。加えて、配列はintやdoubleなどのプリミティブ型を直接格納できますが、Listではプリミティブ型を扱えないため、IntegerやDoubleといったラッパークラスを使う必要がある点にも注意しましょう。

java.utilのインポート

ListはJavaが元々用意してくれているインタフェースです。

よく分からないと思いますが、要はJavaで元々用意された便利ツールです。

その便利ツールListはインポートすることで使用できるようになります。

Listのインポートの方法は以下の通りです。

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

今回は、特にArrayListについて解説していくので、ArrayListもインポートしておきます。

インポート文はmain文や、クラスの外に記述してください。

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

public class Sample {
    public static void main(String[] args) {

    }
}

ArrayListの宣言方法

W3Schoolsでも紹介されているように、ArrayListはJavaで最もよく使われるList実装です。ArrayListの宣言方法は主に以下の3つです。

  1. List<データ型> リスト名 = new ArrayList<データ型>();
  2. List<データ型> リスト名 = new ArrayList<データ型>( 要素数 );
  3. List<データ型> リスト名 = new ArrayList<データ型>( Arrays.asList(要素) );

① List<データ型> リスト名 = new ArrayList<データ型>();

最も基本的なArrayListの宣言方法です。

データ型は、リストに格納したいデータの型を指定し、リスト名は自分の好きな名前でOKです。

List<String> name = new ArrayList<String>();

これで、何もデータが格納されていないArrayList「name」が作成されました。

② List<データ型> リスト名 = new ArrayList<データ型>( 要素数 );

この宣言方法では、あらかじめArrayListの初期容量(キャパシティ)を指定しておくことができます。これは「要素数の上限」ではなく、内部配列の初期サイズのヒントにすぎません。想定よりデータが増えても自動で拡張されるので安心してください。

初めからたくさんのデータを格納することが分かっている場合に使用すると、内部でのサイズ変更(再配置)の回数が減り、わずかに効率が良くなります。

List<String> name = new ArrayList<String>(1000);

これで、初期容量1000のArrayList「name」が作成されました(要素はまだ0個です)。

③ List<データ型> リスト名 = new ArrayList<データ型>( Arrays.asList(要素) );

この宣言方法では、宣言時に初期値を設定することができます。

初めから格納するデータが決まっている場合に使用すると良いです。

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

これで、「太郎」、「次郎」、「三郎」が格納されたArrayList「name」が作成されました。

ArrayListの基本的な使い方【add・get・set・remove】

ここからは、実務や課題で最も使う頻度が高い「要素の追加・取得・更新・削除」の方法を、実行結果付きで解説します。

要素を追加する(add)

宣言後にデータを格納するにはadd()メソッドを使用します。

リスト名.add( データ );

add()メソッドを使用すると、ArrayListの末尾にデータを追加します。

List<String> name = new ArrayList<String>();

name.add("太郎");
name.add("次郎");
name.add("三郎");

System.out.println(name);

実行結果

[太郎, 次郎, 三郎]

また、add(インデックス, データ)のように第一引数にインデックスを指定すると、任意の位置にデータを挿入することもできます。

name.add(1, "四郎");
System.out.println(name);

実行結果

[太郎, 四郎, 次郎, 三郎]

要素を取得する(get)

リストの中の要素を取得するにはget()メソッドを使用します。インデックスは配列と同じく0から始まります。

リスト名.get( インデックス );
List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

String first = name.get(0);
System.out.println(first);

実行結果

太郎

存在しないインデックスを指定するとIndexOutOfBoundsExceptionが発生するので注意しましょう。

要素を更新する(set)

既にある要素の値を書き換えるにはset()メソッドを使用します。

リスト名.set( インデックス, 新しいデータ );
List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

name.set(1, "次郎(改)");
System.out.println(name);

実行結果

[太郎, 次郎(改), 三郎]

要素を削除する(remove)

要素を削除するにはremove()メソッドを使用しますが、引数の型によって動作が変わる点に注意が必要です。

  • remove(int index):インデックスを指定して削除
  • remove(Object o):値そのものを指定して削除(最初に見つかった要素のみ)
List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

name.remove(0);          // インデックス0を削除
System.out.println(name);

name.remove("三郎");      // 値"三郎"を削除
System.out.println(name);

実行結果

[次郎, 三郎]
[次郎]

Integer型のListでremove(1)のように数値を渡すと、意図せず「インデックス1」として解釈されてしまう点もよくある間違いなので覚えておきましょう。

要素数を取得する(size)

リストに格納されている要素の数はsize()メソッドで取得できます。

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));
System.out.println(name.size());

実行結果

3

Listの繰り返し処理(イテレーション)

Listの全要素を順番に処理したい場合は、主に以下の3つの方法があります。

拡張for文(for-each)

最もシンプルでよく使われる書き方です。

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

for (String n : name) {
    System.out.println(n);
}

実行結果

太郎
次郎
三郎

Iteratorを使う方法

ループ中に要素を安全に削除したい場合は、Iteratorを使います。拡張for文や通常のfor文の途中でremove()を呼ぶとConcurrentModificationExceptionが発生するため、ループ中に削除する可能性がある場合はIteratorを使いましょう。

import java.util.Iterator;

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));
Iterator<String> it = name.iterator();

while (it.hasNext()) {
    String n = it.next();
    if (n.equals("次郎")) {
        it.remove();
    }
}
System.out.println(name);

実行結果

[太郎, 三郎]

通常のfor文(インデックス利用)

インデックスそのものを使いたい場合は、通常のfor文も使えます。

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

for (int i = 0; i < name.size(); i++) {
    System.out.println(i + ":" + name.get(i));
}

実行結果

0:太郎
1:次郎
2:三郎

Listの便利な操作(検索・ソート・変換)

codejava.netのチュートリアルでも紹介されているように、Listには検索・ソート・配列変換などの便利な操作が数多く用意されています。

要素を検索する(contains・indexOf)

List<String> name = new ArrayList<String>(Arrays.asList("太郎", "次郎", "三郎"));

System.out.println(name.contains("次郎"));
System.out.println(name.indexOf("三郎"));

実行結果

true
2

contains()は要素が存在するかどうかをtrue/falseで返し、indexOf()は要素のインデックス(存在しない場合は-1)を返します。

リストをソートする(Collections.sort)

import java.util.Collections;

List<String> name = new ArrayList<String>(Arrays.asList("三郎", "太郎", "次郎"));
Collections.sort(name);

System.out.println(name);

実行結果

[三郎, 太郎, 次郎]

文字列は辞書順(Unicodeコードポイント順)でソートされます。数値のListなら昇順に並び替わります。

Listと配列を相互変換する

配列からListを作る場合はArrays.asList()、ListからListを配列に変換する場合はtoArray()を使います。

// 配列 → List
String[] array = {"太郎", "次郎", "三郎"};
List<String> list = new ArrayList<String>(Arrays.asList(array));

// List → 配列
String[] backToArray = list.toArray(new String[0]);

System.out.println(list);
System.out.println(Arrays.toString(backToArray));

実行結果

[太郎, 次郎, 三郎]
[太郎, 次郎, 三郎]

ArrayListとLinkedList・Vectorの違い

Listインターフェースの実装クラスはArrayList以外にも複数あります。DigitalOceanのチュートリアルでも解説されているように、それぞれ内部構造が異なり、得意な処理も変わってきます。

実装クラス 内部構造 要素取得(get)の速度 先頭・中間への追加削除速度 スレッドセーフ 特徴
ArrayList 可変長配列 速い(インデックス直接参照) 遅め(要素のシフトが発生) ✗ 最もよく使われる標準的な実装
LinkedList 双方向連結リスト 遅い(先頭から順にたどる) 速い(先頭・末尾の追加削除) ✗ Queue/Dequeとしても使える
Vector 可変長配列 速い ArrayListとほぼ同じ ✓(同期化されている) レガシーなクラス。新規開発では非推奨

どちらを使うべきか

  • 要素の取得(get)を頻繁に行う → ArrayList
  • 先頭・末尾への追加・削除が多い(キューやスタック的な使い方) → LinkedList
  • マルチスレッドで同期が必要 → ArrayListをCollections.synchronizedList()でラップするのが一般的(Vectorは基本的に使わない)

特別な理由がない限り、まずはArrayListを選んでおけば問題ありません。実際、実務でもArrayListが使われるケースが大半です。

まとめ

今回はJavaのList(主にArrayList)の使い方について解説しました。

  • Listは配列と似ているが、要素数を自由に増減できる点が大きな違い
  • 配列はプリミティブ型を扱えるが、Listはラッパークラスが必要
  • ArrayListの宣言方法は主に3パターン(空の作成/初期容量指定/初期値指定)
  • add・get・set・remove・sizeでListの基本操作ができる
  • 繰り返し処理は拡張for文・Iterator・通常のfor文の3種類が使える
  • 検索・ソート・配列との相互変換などの応用操作も覚えておくと実務で役立つ
  • 実装クラスはArrayList以外にLinkedList・Vectorなどがあるが、基本的にはArrayListを選べばよい

Listは配列よりも柔軟に扱えるため、Javaの開発では非常によく使われます。まずはArrayListの基本操作をしっかり押さえておきましょう。

配列について復習したい方は、こちらの記事も参考にしてください。

【Java】配列の使い方【初心者向け】

参考にしたサイト

コメント

タイトルとURLをコピーしました