なぜJava Vectorはレガシークラスと見なされているのですか。
並行処理を使用している場合、その使用は有効ではありませんか?
手動でオブジェクトを同期させたくなくて、(CopyOnWriteArrayList
がそうであるように)基礎となる配列の新しいコピーを作らずにスレッドセーフなコレクションを使いたいだけなら、Vector
を使うのはいいのですか?
Stack
のサブクラスであるVector
はどうなりますか?代わりに何を使うべきですか?
Vector
は、個々の操作ごとに同期します。それはあなたがしたいことはほとんどありません。
一般に、操作のシーケンス全体を同期します。個々の操作の同期は安全性が低くなります(たとえば、Vector
を反復処理する場合は、ロックを解除して、コレクションを同時に変更するユーザーを回避する必要があります。これにより、反復スレッドでConcurrentModificationException
が発生します)遅い(なぜ十分なときにロックを繰り返し解除するのか)
もちろん、必要がない場合でもロックのオーバーヘッドもあります。
基本的に、ほとんどの状況での同期に対する非常に欠陥のあるアプローチです。 ミスター・ブライアン・ヘンクが指摘したように、 Collections.synchronizedList
などの呼び出しを使用してコレクションを飾ることができます-Vector
が両方を組み合わせるという事実「すべての操作を同期する」ビットを使用した「サイズ変更された配列」コレクションの実装は、設計が不十分な別の例です。デコレーションアプローチにより、懸念事項をより明確に分離できます。
同等のStack
については、Deque
/ArrayDeque
を見てみましょう。
Vectorは1.0の一部でした - 元の実装には2つの欠点がありました。
1.命名: ベクトルは実際には配列としてアクセスできる単なるリストなので、ArrayList
と呼ばれるべきです(これはVector
の代わりとなるJava 1.2コレクションです)。
2.並行性: すべてのget()
、set()
メソッドはsynchronized
なので、同期をきめ細かく制御することはできません。
ArrayList
とVector
の間に大きな違いはありませんが、ArrayList
を使うべきです。
APIドキュメントより.
Java 2プラットフォームv1.2以降、このクラスはListインタフェースを実装するために改良され、Java Collections Frameworkのメンバになりました。新しいコレクションの実装とは異なり、Vectorは同期されています。
Vectorの使用に関してすでに述べた回答以外にも、Vectorには、Listインタフェースとは異なる列挙や要素の取得に関するメソッドが多数あります。開発者(特に1.2より前のJavaを学んだ人)は、コード。列挙は高速ですが、コレクションが反復中に変更されたかどうかをチェックしないため、問題が発生する可能性があります。また、Vectorが同期のために選択される可能性がありますこれらのメソッドを使用すると、多くのコードがVectorに結合されるため、別のList実装に置き換えるのは簡単ではありません。
スレッドセーフでないコレクションからスレッドセーフなコレクションを取得するには、Java.util.Collection
で synchronizedCollection/List メソッドを使用します。
Java.util.Stack
はJava.util.Vector
の同期オーバーヘッドを継承していますが、これは通常正当化されません。
ただし、それはそれ以上のものを継承しています。 Java.util.Stack extends Java.util.Vector
がオブジェクト指向設計の誤りです。純粋主義者は、それが伝統的にスタックに関連した操作(すなわち、プッシュ、ポップ、ピーク、サイズ)を超えた多くの方法も提供することに気付くでしょう。 search
、elementAt
、setElementAt
、remove
、および他の多くのランダムアクセス操作を実行することもできます。 Stack
の非スタック操作の使用を控えるのは基本的にユーザー次第です。
これらのパフォーマンスとOOP設計上の理由から、 JavaDoc for Java.util.Stack
は自然な置き換えとして ArrayDeque
を推奨します。 (dequeはスタック以上のものですが、少なくともすべてへのランダムアクセスを提供するのではなく、両端を操作することに制限されています。)