広告

Java : List の初期化方法いろいろ

本記事では、List の初期値を設定する方法を5つご紹介します。
その中で、インスタンスイニシャライザはあまりおすすめしない理由も補足します。


リストの初期化

簡単なまとめ

初期化方法 おすすめ度 不変オブジェクト サイズの変わる操作
List.of ☆☆☆ ×
Arrays.asList ☆☆ × ×
リストのコンストラクタ ☆☆ ×
Collections.addAll ☆☆ ×
インスタンスイニシャライザ ×

関連 : 不変オブジェクト(イミュータブル) とは


コード例

初期化方法 コード例
List.of
final List<String> list = List.of("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]
Arrays.asList
final List<String> list = Arrays.asList("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]
リストのコンストラクタ
final List<String> list = new ArrayList<>(List.of("aaa", "bbb", "ccc"));
System.out.println(list); // [aaa, bbb, ccc]
Collections.addAll
final List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");

System.out.println(list); // [aaa, bbb, ccc]
インスタンスイニシャライザ
final List<String> list = new ArrayList<>() {
    {
        add("aaa");
        add("bbb");
        add("ccc");
    }
};
System.out.println(list); // [aaa, bbb, ccc]

List.of

static <E> List<E> of(E... elements)
任意の数の要素を含む変更不可能なリストを返します。

もし List に対して変更が必要なければ、List.of メソッドを使うのがおすすめです。
List.of メソッドは、不変オブジェクト である List を作成します。

final List<String> list = List.of("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

作成した List は不変オブジェクトです。
そのため、List を変更しようとすると

が発生します。

List の要素を変更する set メソッドを使う例です。

final List<String> list = List.of("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

list.set(1, "XXX"); // UnsupportedOperationException 発生

Arrays.asList

public static <T> List<T> asList(T... a)
指定された配列に連動する固定サイズのリストを返します。

Arrays クラスの asList メソッドを使う例です。

final List<String> list = Arrays.asList("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

List.of メソッドに似ていますが、要素の変更は OK です。

final List<String> list = Arrays.asList("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

// 要素の変更はOK
list.set(1, "XXX");
System.out.println(list); // [aaa, XXX, ccc]

ただし、リストのサイズが変わる操作 (追加や削除など) はできません。

final List<String> list = Arrays.asList("aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

// リストのサイズが変わる操作はNG
list.add("YYY"); // UnsupportedOperationException 発生

リストのコンストラクタ

public ArrayList(Collection<? extends E> c)
指定されたコレクションの要素が含まれているリストを、コレクションのイテレータによって返される順序で構築します。

ArrayList クラスは List インタフェースの実装の1つです。
コンストラクタに Collection を指定すことで要素を初期化できます。

(ちなみに List は Collection のサブインタフェースです)

クラス図

少し冗長かもしれませんが、ArrayList のコンストラクタと

  • List.of メソッド
  • Arrays.asList メソッド

を組み合わせて List を初期化できます。

もちろん、ArrayList なのでリストの変更 (追加・削除) が可能です。

【 List.of を使った例 】

final List<String> list = new ArrayList<>(List.of("aaa", "bbb", "ccc"));
System.out.println(list); // [aaa, bbb, ccc]

list.add("XXX");
System.out.println(list); // [aaa, bbb, ccc, XXX]

※今回は ArrayList を使いましたが、他の実装 … 例えば LinkedList を使っても OK です。

Collections.addAll

public static <T> boolean addAll(Collection<? super T> c, T... elements)
指定されたすべての要素を指定されたコレクションに追加します。

もし1行の初期化にこだわらないのであれば、Collections.addAll メソッドが使えます。

final List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

もちろん、ArrayList なのでリストの変更 (追加・削除) が可能です。

final List<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
System.out.println(list); // [aaa, bbb, ccc]

list.add("XXX");
System.out.println(list); // [aaa, bbb, ccc, XXX]

インスタンスイニシャライザ

インスタンスイニシャライザを使った初期化も可能です。
具体的な例で見てみましょう。

final List<String> list = new ArrayList<>() {
    {
        add("aaa");
        add("bbb");
        add("ccc");
    }
};
System.out.println(list); // [aaa, bbb, ccc]

これは、分解すると2つの構造に分けられます。
最初の { ... } は匿名クラス(Anonymous Class) の宣言です。

final List<String> list = new ArrayList<>() {
    ... 匿名クラスの宣言 ...
};

そして、その中の { ... } がインスタンスイニシャライザです。

final List<String> list = new ArrayList<>() {
    {
        ... インスタンスイニシャライザ ...
    }
};

インスタンスイニシャライザはさておき、匿名クラスには注意点があります。

  • 匿名クラスは、内部クラスの1つです。そのため、外側のクラス参照を暗黙的に保持します。
    • これはガベージ・コレクタによるメモリ解放を阻害するおそれがあります。

  • AraryList は serialVersionUID を定義していますが、その匿名クラスは serialVersionUID を定義していません。
    • シリアライズするときは特に注意が必要です。
    • 静的解析ツール (lint など) で「serialVersionUID を定義していませんよ」と警告されることがあります。
    • 外側のクラス参照を持つので、意図せず外側のクラスまでシリアライズしてしまうリスクがあります。

もし使うのであれば、匿名クラスとインスタンスイニシャライザをよく理解してから使うことをおすすめします。

参考 : [Java] 匿名クラスとインスタンスイニシャライザを使って初期化したデータのシリアライズに失敗した話

まとめ

本記事では、List の初期化方法を5つご紹介しました。

  • 不変オブジェクトなら … List.of メソッド
  • 可変オブジェクトなら … リストのコンストラクタ or Collections.addAll メソッド

を使うのがおすすめです。


関連記事

ページの先頭へ