Java 9では、リスト用の新しいファクトリメソッド List.of
が導入されました。
List<String> strings = List.of("first", "second");
以前のオプションと新しいオプションの違いは何ですか?つまり、これの違いは何ですか:
Arrays.asList(1, 2, 3);
この:
List.of(1, 2, 3);
Arrays.asList
は可変リストを返しますが、List.of
が返すリストは immutable です。
List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK
List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException
Arrays.asList
はnull要素を許可しますが、List.of
は許可しません:
List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException
contains
は、nullとは異なる動作をします。
List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false
List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException
Arrays.asList
は渡された配列のビューを返すため、配列への変更はリストにも反映されます。 List.of
の場合、これは正しくありません。
Integer[] array = {1,2,3};
List<Integer> list = Arrays.asList(array);
array[1] = 10;
System.out.println(list); // Prints [1, 10, 3]
Integer[] array = {1,2,3};
List<Integer> list = List.of(array);
array[1] = 10;
System.out.println(list); // Prints [1, 2, 3]
Arrays.asList
と List.of
の違いStuart Marks(または以前のバージョン)の JavaDocs およびこの talk を参照してください。
コード例には次を使用します。
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
List.of
を構造的に変更しようとすると、UnsupportedOperationException
になります。これには、add、set、removeなどの操作が含まれます。ただし、リスト内のオブジェクトの内容は変更できます(オブジェクトが不変でない場合)。そのため、リストは「完全に不変」ではありません。
これは、 Collections.unmodifiableList
で作成された変更不可能なリストと同じ運命です。このリストのみが元のリストのviewなので、元のリストを変更すると変更できます。
Arrays.asList
は完全に不変ではなく、set
に制限はありません。
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
同様に、バッキング配列を変更すると(保持している場合)、リストが変更されます。
構造的な不変性には、防御的なコーディング、同時実行性、セキュリティに関連する多くの副作用が伴いますが、これらはこの答えの範囲を超えています。
List.of
およびJava 1.5以降のコレクションでは、null
を要素として使用できません。 null
を要素またはルックアップとして渡そうとすると、NullPointerException
になります。
Arrays.asList
は1.2(Collections Framework)のコレクションであるため、null
sを使用できます。
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
List.of
はJava 9で導入されており、このメソッドで作成されたリストは独自の(バイナリ)シリアル化された形式を持っているため、以前のJDKバージョンではデシリアライズできません(バイナリ互換性なし)。ただし、たとえばJSONでデシリアライズできます。
Arrays.asList
は内部的にnew ArrayList
を呼び出し、参照の不等式を保証します。
List.of
は内部実装に依存します。返されるインスタンスは参照の等価性を持つことができますが、これは保証されないため、それに依存することはできません。
asList1 == asList2; // false
listOf1 == listOf2; // true or false
リストの作成方法やサポートする操作に関係なく、リストに同じ要素が同じ順序で含まれている場合、リストは等しい( List.equals
を介して)と言う価値があります。
asList.equals(listOf); // true i.f.f. same elements in same order
List.of
のリスト内の要素の数が2以下の場合、要素は特殊な(内部)クラスのフィールドに格納されます。例は、2つの要素(部分ソース)を格納するリストです:
static final class List2<E> extends AbstractImmutableList<E> {
private final E e0;
private final E e1;
List2(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
それ以外の場合は、Arrays.asList
と同様の方法で配列に格納されます。
フィールドベース(size <2)のList.of
実装は、一部の操作でわずかに高速に実行されます。例として、size()
は配列の長さをフェッチせずに定数を返すことができ、contains(E e)
は反復オーバーヘッドを必要としません。
List.of
を使用して変更不可能なリストを作成することも高速です。上記のコンストラクターを2つの参照割り当て(および任意の量の要素に対するもの)と比較します
Collections.unmodifiableList(Arrays.asList(...));
2つのリストとその他のオーバーヘッドが作成されます。スペースの観点から、UnmodifiableList
ラッパーといくつかのペニーを保存します。最終的に、同等のHashSet
の節約はより説得力があります。
結論の時間:変更しないリストが必要な場合はList.of
を使用し、変更可能なリストが必要な場合はArrays.asList
を使用します(上記を参照)。
List.ofとArrays.asListの違いを要約しましょう
List.of
は、データセットが少なく変更されていない場合に最適に使用でき、Arrays.asList
は、大きく動的なデータセットの場合に最適に使用できます。
List.of
は、フィールドベースの実装を持ち、固定オーバーヘッドと要素ごとの両方の観点でヒープスペースを消費しないため、オーバーヘッドスペースが非常に少なくなります。 Arrays.asList
は、初期化中にヒープ内により多くのオブジェクトを作成するため、より多くのオーバーヘッドスペースを必要とします。
List.of
によって返されるコレクションは不変であるためスレッドセーフであるのに対し、Arrays.asList
によって返されるコレクションは変更可能でスレッドセーフではありません。 (不変のコレクションインスタンスは、通常、可変の対応するインスタンスよりもはるかに少ないメモリを消費します。)
List.of
はnull要素を許可しませんが、Arrays.asList
はnull要素を許可します。