検証PCのスペック
- OS: Windows 7 64bit Professional
- CPU: Intel Core i5-3470 3.20GHz
- メモリ: 8.00GB
Javadocの定義
まずは Javadoc を確認。
Arrays.asList()
修飾子と型 | メソッド | 説明 |
---|---|---|
static <T> List<T> |
asList(T... a) |
指定された配列に連動する固定サイズのリストを返します。 |
List.of()
修飾子と型 | メソッド | 説明 |
---|---|---|
static <E> List<E> |
of () |
ゼロ要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1) |
1つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2) |
2つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3) |
3つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4) |
4つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5) |
5つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5, E e6) |
6つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5, E e6, E e7) |
7つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) |
8つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) |
9つの要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) |
10個の要素を含む不変のリストを返します。 |
static <E> List<E> |
of (E... elements) |
任意の数の要素を含む不変のリストを返します。 |
違い
Arrays.asList()
は可変長引数を受け取るメソッドしかないのに対し、
List.of()
は可変長以外にも0~10の引数を受け取るメソッドが個別で定義されている。
それぞれのソースコード
Oracle JDK を Eclipse で使えるようにして、それぞれのメソッド定義を参照した。
Arrays.asList()
@SafeVarargs @SuppressWarnings("varargs") public static <T> List<T> asList(T... a) { return new ArrayList<>(a); // 注:内部クラスの ArrayList(下記)を呼んでいる } private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override public int size() { return a.length; } @Override public Object[] toArray() { return Arrays.copyOf(a, a.length, Object[].class); } @Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.getClass()); System.arraycopy(this.a, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } @Override public E get(int index) { return a[index]; } @Override public E set(int index, E element) { E oldValue = a[index]; a[index] = element; return oldValue; } @Override public int indexOf(Object o) { E[] a = this.a; if (o == null) { for (int i = 0; i < a.length; i++) if (a[i] == null) return i; } else { for (int i = 0; i < a.length; i++) if (o.equals(a[i])) return i; } return -1; } @Override public boolean contains(Object o) { return indexOf(o) >= 0; } @Override public Spliterator<E> spliterator() { return Spliterators.spliterator(a, Spliterator.ORDERED); } @Override public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); for (E e : a) { action.accept(e); } } @Override public void replaceAll(UnaryOperator<E> operator) { Objects.requireNonNull(operator); E[] a = this.a; for (int i = 0; i < a.length; i++) { a[i] = operator.apply(a[i]); } } @Override public void sort(Comparator<? super E> c) { Arrays.sort(a, c); } @Override public Iterator<E> iterator() { return new ArrayItr<>(a); } }
List.of()
static <E> List<E> of() { return ImmutableCollections.List0.instance(); } static <E> List<E> of(E e1) { return new ImmutableCollections.List1<>(e1); } static <E> List<E> of(E e1, E e2) { return new ImmutableCollections.List2<>(e1, e2); } static <E> List<E> of(E e1, E e2, E e3) { return new ImmutableCollections.ListN<>(e1, e2, e3); } // : // : @SafeVarargs @SuppressWarnings("varargs") static <E> List<E> of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: return ImmutableCollections.List0.instance(); case 1: return new ImmutableCollections.List1<>(elements[0]); case 2: return new ImmutableCollections.List2<>(elements[0], elements[1]); default: return new ImmutableCollections.ListN<>(elements); } } // ImmutableCollections.ListXの実装の一つ // List0, List1, List2, ListN があるが割愛 static final class List1<E> extends AbstractImmutableList<E> { @Stable private final E e0; List1(E e0) { this.e0 = Objects.requireNonNull(e0); } @Override public int size() { return 1; } @Override public E get(int index) { Objects.checkIndex(index, 1); return e0; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } private Object writeReplace() { return new CollSer(CollSer.IMM_LIST, e0); } @Override public boolean contains(Object o) { return o.equals(e0); // implicit nullcheck of o } @Override public int hashCode() { return 31 + e0.hashCode(); } } // ↑の継承元 abstract static class AbstractImmutableList<E> extends AbstractList<E> implements RandomAccess, Serializable { @Override public boolean add(E e) { throw uoe(); } // 注:throw UnsupportedOperationException @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } @Override public void clear() { throw uoe(); } @Override public boolean remove(Object o) { throw uoe(); } @Override public boolean removeAll(Collection<?> c) { throw uoe(); } @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } @Override public boolean retainAll(Collection<?> c) { throw uoe(); } @Override public void sort(Comparator<? super E> c) { throw uoe(); } }
速度の検証
内部的には結構違うみたいなので、とりあえず速度を計測してみます。
内容
1要素・10要素・0要素のリストを、Arrays.asList()
とList.of()
で生成。
1億回繰り返して、かかった時間を取得。
それを10回ずつ繰り返して、平均を出力。
ソースコード
import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Java9Test { public static void main(String[] args) { // 1要素のリストを生成 List<Long> asListResult = new ArrayList<>(); List<Long> ofResult = new ArrayList<>(); for (int i = 0; i < 10; i++) { asListResult.add(arraysAsList()); ofResult.add(listOf()); } System.out.println("asListResult: " + asListResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); System.out.println("ofResult: " + ofResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); // 10要素のリストを生成 List<Long> asListManyResult = new ArrayList<>(); List<Long> ofManyResult = new ArrayList<>(); for (int i = 0; i < 10; i++) { asListManyResult.add(arraysAsListMany()); ofManyResult.add(listOfMany()); } System.out.println("asListManyResult: " + asListManyResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); System.out.println("ofManyResult: " + ofManyResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); // 0要素のリストを生成 List<Long> asListZeroResult = new ArrayList<>(); List<Long> ofZeroResult = new ArrayList<>(); for (int i = 0; i < 10; i++) { asListZeroResult.add(arraysAsListZero()); ofZeroResult.add(listOfZero()); } System.out.println("asListZeroResult: " + asListZeroResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); System.out.println("ofZeroResult: " + ofZeroResult.stream().collect(Collectors.averagingLong((l) -> l)).toString()); } private static long listOf() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = List.of("a"); } return (System.nanoTime() - start) / 1_000; } private static long arraysAsList() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = Arrays.asList("a"); } return (System.nanoTime() - start) / 1_000; } private static long listOfMany() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"); } return (System.nanoTime() - start) / 1_000; } private static long arraysAsListMany() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"); } return (System.nanoTime() - start) / 1_000; } private static long listOfZero() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = List.of(); } return (System.nanoTime() - start) / 1_000; } private static long arraysAsListZero() { long start = System.nanoTime(); List<String> a; for (int i = 0; i < 100_000_000; i++) { a = Arrays.asList(); } return (System.nanoTime() - start) / 1_000; } }
結果
単位はµs(マイクロ秒)です。
// 1要素のリストの生成時間 asListResult: 1812.4 ofResult: 2865.1 // 10要素のリストの生成時間 asListManyResult: 3285.1 ofManyResult: 2533388.9 // 0要素のリストの生成時間 asListZeroResult: 1159.2 ofZeroResult: 451.8
List.of()
遅すぎやしませんか……?
まとめ
正しく計測できているか不安ですが、基本的にArrays.asList()
のほうが、リストの生成は速いみたいです。
特に要素数が多い場合は、List.of()
がだいぶ遅くなるようです。
ただし、0要素のリストを生成する場合は、List.of()
はキャッシュしてあるインスタンスを返すため、速いようです。
List.of()
の明日はどっちだ!?
要素の取得の速度については測っていないので誰か試してくだしあ(丸投げ)。