Java APIのドキュメントによると 以下についてCollections.addAll
この便利なメソッドの動作はc.addAll(Arrays.asList(elements))の動作と同じですが、このメソッドはほとんどの実装で著しく高速に実行される可能性があります。
だから私が正しく理解すれば、a)はb)より遅いです:
a)
Collection<Integer> col = new ArrayList<Integer>();
col.addAll(Arrays.asList(1, 2, 3, 4, 5));
b)
Collection<Integer> col = new ArrayList<Integer>();
// Collections.addAll(col, Arrays.asList(1, 2, 3, 4, 5)); <-- won't compile
Collections.addAll(col, 1, 2, 3, 4, 5);
誰かが私に説明できますか、それはなぜですか?
編集:修正されたコード例。 thxから polygenelubricants
それらの2つを詳しく見てみましょう。
_// a) col.addAll(Arrays.asList(1, 2, 3, 4, 5));
_
ここで何が起こるかです:
Integer[]
_を作成しますArrays.asList
_は、配列に基づく_List<Integer>
_を作成しますaddAll
_Collection<Integer>
_を使用して_Iterator<Integer>
_を反復します_// b) Collections.addAll(col, 1, 2, 3, 4, 5);
_
ここで何が起こるかです:
Integer[]
_を作成しますaddAll
は配列を反復処理します(_Iterable<Integer>
_の代わりに)_b)
_の方が高速であることがわかります。
Arrays.asList
_の呼び出しはスキップされます。つまり、中間List
は作成されません。Iterator
を使用するよりも速くなる可能性があります。そうは言っても、プロファイリングが別の方法で示していない限り、その差は「有意」である可能性は低いです。時期尚早に最適化しないでください。 Javaコレクションフレームワーククラスは配列よりも遅い場合がありますが、ほとんどのアプリケーションでは十分に機能します。
Collections.addAll(Collection<? super T> c, T... elements)
-可変引数、つまり配列ベースCollection.addAll(Collection<? extends E> c)
-Collection
- basedCollections.addAll(col, arr)
を使用できます。Collection
から要素を追加する場合は、col.addAll(otherCol)
を使用します。Collections.addAll(col, otherCol.toArray())
それがより速くなるかもしれない唯一の理由は、それが配列をラップするだけなので比較的安価であるべきであるArrays.asListへの呼び出しを回避することです。 LinkedListなどの一部のコレクション実装は、要素を追加する前に、渡されたコレクションを配列に変換し直し、オーバーヘッドを追加します。
一方、ArrayList.addAllは、要素を追加する前に必要なスペースを1回割り当てるため、Collections.addAllがバッキング配列の複数のサイズ変更を必要とする場合ははるかに高速になります。
要約すると、Collections.addAllは、いくつかの要素のみをコレクションに繰り返し追加する方が高速である可能性がありますが、このケースがパフォーマンスのボトルネックになることはないと思います。
@polygenelubricantsで言及されている各ステップの(概算)関連する時間複雑性コスト関数を次に示します。
a)引数リストの3回の反復〜= C(3N)
b)引数リストの2回の反復〜= C(2N)
明らかに、両方ともO(N)ですが、アプローチb)は、アプローチa)と比較して〜Nの比較を保存します。うまくいけば、これは定量的な説明に興味を持っていた人には役に立ちます。
(SE Platform 6でビルドしましょう)
それはすべて実際のコレクションの実装に依存します。あなたの例では
Collection<Integer> col = new ArrayList<Integer>();
addAll
のArrayList
メソッドはオーバーライドされます。反復は一切ありません。ここにソースがあります:
_public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacity(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
_
お気づきかもしれませんが、c.toArray()
も実際の実装によって異なります。繰り返しますが、あなたの場合、Arrays.asList()
はArrayList
となり、toArray()
メソッドのバージョンは次のようになります。
_public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
_
この静的メソッドは_System.arraycopy
_に基づいています
したがって、ここで扱うのは_System.arraycopy
_の2つの呼び出しです。これは、現在のオペレーティングシステム用に特に最適化されたネイティブメソッドであるため、それほど悪くありません。
それで、それをすべてpolygenelubricantsのスタイルで要約すると:
Integer[]
_を作成しますArrays.asList
_は_ArrayList<Integer>
_を作成しますArrayList.addAll
_呼び出しSystem.arraycopy(size)
x2、サイズ= 5配列内の5つのオブジェクトの場合、_Collections.addAll
_の方が高速です。しかし、そのような小さな配列サイズとは無関係です。一方、たとえば、配列内の100k要素の場合、col.addAll(Arrays.asList(...))
ははるかに効率的です。これは、ネイティブメソッドの場合、100k回の反復/コピー操作ではなく、単一のmemcpy/memmoveを処理するためです。 。
そして再び、それはすべてコレクションの実装に依存します。たとえばLinkedList
は、期待どおりに反復します。