1. 概要

このクイックチュートリアルでは、ワンライナーを使用してリストを初期化する方法を調査します。

2. 配列から作成

配列からリストを作成できます。 配列リテラルのおかげで、1行で初期化できます。

List<String> list = Arrays.asList(new String[]{"foo", "bar"});

配列の作成を処理するためにvarargsメカニズムを信頼できます。 これにより、より簡潔で読みやすいコードを記述できます。

@Test
public void givenArraysAsList_thenInitialiseList() {
    List<String> list = Arrays.asList("foo", "bar");

    assertTrue(list.contains("foo"));
}

このコードの結果インスタンスはListインターフェイスを実装しますが、java .util.ArrayListまたはLinkedListではありません。代わりに、元の配列に基づくListです。 、これには、このセクションの残りの部分で説明する2つの意味があります。

クラスの名前はたまたまArrayListですが、 java.util.Arraysパッケージに含まれています。

2.1. 固定サイズ

Arrays.asListの結果インスタンスのサイズは固定されています。

@Test(expected = UnsupportedOperationException.class)
public void givenArraysAsList_whenAdd_thenUnsupportedException() {
    List<String> list = Arrays.asList("foo", "bar");

    list.add("baz");
}

2.2. 共有リファレンス

元の配列とリストは、オブジェクトへの同じ参照を共有します。

@Test
public void givenArraysAsList_whenCreated_thenShareReference(){
    String[] array = {"foo", "bar"};
    List<String> list = Arrays.asList(array);
    array[0] = "baz";
 
    assertEquals("baz", list.get(0));
}

3. ストリームから作成(Java 8)

簡単に変換できますストリームあらゆる種類にコレクション。

したがって、 Streams のファクトリメソッドを使用すると、リストを1行で作成および初期化できます。

@Test
public void givenStream_thenInitializeList(){
    List<String> list = Stream.of("foo", "bar")
      .collect(Collectors.toList());
		
    assertTrue(list.contains("foo"));
}

ここで、 Collectors.toList()は、返されたListの正確な実装を保証するものではないことに注意してください。

返されたインスタンスの可変性、直列化可能性、またはスレッドセーフに関する一般的な契約はありません。したがって、コードはこれらのプロパティのいずれにも依存しないようにする必要があります。

一部のソースは、 Stream.of(…).collect(…)の方が Arrays.asList()よりもメモリとパフォーマンスのフットプリントが大きい可能性があることを強調しています。 しかし、ほとんどすべての場合、それはほとんど違いがないほどのマイクロ最適化です。

4. ファクトリメソッド(Java 9)

JDK 9では、コレクションに便利なファクトリメソッドがいくつか導入されています。

List<String> list = List.of("foo", "bar", "baz");
Set<String> set = Set.of("foo", "bar", "baz");

1つの重要な詳細は、返されるインスタンスが不変であるということです。それ以外に、ファクトリメソッドにはスペース効率とスレッドセーフにいくつかの利点があります。

このトピックについては、この記事で詳しく説明しています。

5. ダブルブレースの初期化

いくつかの場所で、次のようなダブルブレース初期化と呼ばれるメソッドを見つけることができます。

@Test
public void givenAnonymousInnerClass_thenInitialiseList() {
    List<String> cities = new ArrayList() {{
        add("New York");
        add("Rio");
        add("Tokyo");
    }};

    assertTrue(cities.contains("New York"));
}

「ダブルブレースの初期化」という名前は、かなり誤解を招く恐れがあります。 構文はコンパクトでエレガントに見えるかもしれませんが、内部で起こっていることを危険なほど隠しています。

Javaには実際には二重中括弧の構文要素はありません。 これらは、このように意図的にフォーマットされた2つのブロックです。

外側の中括弧を使用して、ArrayListのサブクラスとなる匿名の内部クラスを宣言します。これらの中括弧内でサブクラスの詳細を宣言できます。

いつものように、インスタンス初期化ブロックを使用できます。これは、中括弧の内側のペアが由来する場所です。

この構文の簡潔さは魅力的です。 ただし、これはアンチパターンと見なされます。

ダブルブレースの初期化の詳細については、こちらの記事をご覧ください。

6. 結論

最新のJavaには、1行でコレクションを作成するためのいくつかのオプションがあります。私たちが選択する方法は、技術的な理由ではなく、ほぼ完全に個人的な好みに依存します。

重要なポイントは、見た目は優雅ですが、匿名内部クラスの初期化のアンチパターン(別名ダブルブレース)には多くのマイナスの副作用があることです。

いつものように、コードはGitHubから入手できます。