1行でのJavaリストの初期化

1行でのJavaリストの初期化

1. 前書き

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

参考文献:

Collections.emptyList() vs. 新しいリストインスタンス

「Collections.emptyList()」と新しいリストインスタンスの違いを学びます。

Java ArrayListのガイド

JavaのArrayListの迅速かつ実用的なガイド

2. 配列から作成

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

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

配列の作成を処理する可変引数メカニズムを信頼できます。 それにより、より簡潔で読みやすいコードを書くことができます。

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

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

The result instance of this code implements the List interface but it isn’t a java.util.ArrayList nor a LinkedList。 代わりに、元の配列に裏打ちされたListであり、2つの意味があります。

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

2.1. 固定サイズ

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

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

    list.add("baz");
}

2.2. 共有リファレンス

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

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

    assertEquals("baz", list.get(0));
}

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

Streamを任意の種類のCollection.に簡単に変換できます

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

@Test
public void givenStream_thenInitializeList(){
    List list = Stream.of("foo", "bar")
      .collect(Collectors.toList());

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

ここで、Collectors.toList()は返されたListの正確な実装を保証しないことをマークする必要があります。

There’s no general contract about the mutability, serializability or thread-safety of the returned instance.したがって、コードはこれらのプロパティのいずれにも依存しないでください。

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

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

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

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

One important detail is the returned instances are immutable。 さらに、ファクトリーメソッドには、スペース効率とスレッドの安全性にいくつかの利点があります。

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

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

いくつかの場所で、次のような‘double brace initialization'というメソッドを見つけることができます。

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

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

‘double brace initialization'という名前はかなり誤解を招くものです。 構文はコンパクトでエレガントに見えるかもしれませんが、ボンネットの下にあるものを危険なほど隠しています。

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

With the outer braces, we declare an anonymous inner class which will be a subclass of the ArrayList.これらの中括弧内で、サブクラスの詳細を宣言できます。

いつものように、インスタンス初期化ブロックを使用することができます。これは、内側のブレースのペアの元です。

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

中括弧の初期化の詳細については、記事hereを参照してください。

6. 結論

Modern Java offers several options to create a Collection in one line.私たちが選んだ方法は、技術的な理由ではなく、ほぼ完全に個人的な好みによるものです。

重要なポイントは、優雅に見えますが、the anti-pattern of anonymous inner class initialization (a.k.a. ‘double brace') has many negative side-effectsであるということです。

いつものように、コードはover on GitHubで利用できます。