Dlaczego klasa Java Vector (i Stack) jest uważana za przestarzałą lub przestarzałą?

677

Dlaczego Java Vector jest uważana za klasę starszą, przestarzałą lub przestarzałą?

Czy jego użycie nie jest prawidłowe podczas pracy z współbieżnością?

A jeśli nie chcę ręcznie synchronizować obiektów i chcę po prostu użyć kolekcji bezpiecznej dla wątków bez konieczności tworzenia nowych kopii podstawowej tablicy (jak to CopyOnWriteArrayListma miejsce), to czy można z niej korzystać Vector?

A Stackco z podklasą Vector, czego powinienem użyć zamiast tego?

fjsj
źródło
Są przestarzałe, ale nie są przestarzałe.
Markiz Lorne

Odpowiedzi:

655

Vectorsynchronizuje każdą operację. Prawie nigdy nie chcesz tego robić.

Zasadniczo chcesz zsynchronizować całą sekwencję operacji. Synchronizacja poszczególnych operacji jest zarówno mniej bezpieczna (jeśli wykonujesz iterację Vector, na przykład, nadal musisz wyjąć blokadę, aby nikt inny nie zmieniał kolekcji w tym samym czasie, co spowodowałoby ConcurrentModificationExceptioniterację w wątku iteracyjnym), ale także wolniej ( po co wielokrotnie wyjmować blokadę, kiedy raz będzie to wystarczające)?

Oczywiście ma również narzut związany z blokowaniem, nawet gdy nie jest to konieczne.

Zasadniczo jest to bardzo wadliwe podejście do synchronizacji w większości sytuacji. Jak zauważył Brian Henk , można udekorować kolekcję za pomocą wywołań takich jak: Collections.synchronizedList- fakt, który Vectorłączy zarówno implementację kolekcji „zmienionej tablicy” z bitem „synchronizuj każdą operację”, jest kolejnym przykładem złego projektu; podejście do dekoracji zapewnia wyraźniejsze oddzielenie problemów.

Jeśli chodzi o Stackodpowiednik - chciałbym zacząć od Deque/ ArrayDequezacząć.

Jon Skeet
źródło
108
„Zasadniczo chcesz zsynchronizować całą sekwencję operacji.” - O to chodzi! Dzięki!
fjsj
7
w której wersji Java Deprecated Vector (obecnie korzystam z Java7). Ale nigdy nie widzę jako przestarzałego? Żegnaj miło Wyjaśnienie ... + 1
Samir Mangroliya,
17
@Samir: To nie jest oficjalnie przestarzałe - po prostu preferowana jest ArrayList.
Jon Skeet,
26
@Samir: Nie, nie zamierzam przewidywać przyszłości.
Jon Skeet,
5
po prostu gr8. wektor nie jest przestarzały. Jest
klasą
82

Vector był częścią 1.0 - oryginalna implementacja miała dwie wady:

1. Nazewnictwo: wektory są tak naprawdę tylko listami, do których można uzyskać dostęp jako tablice, więc należy je nazwać ArrayList(w zamian za kolekcje Java 1.2 Vector).

2. współbieżności: Wszystko z get(), set()metody są synchronized, więc nie można się drobnoziarnisty kontrolę nad synchronizacją.

Nie ma dużej różnicy między ArrayListi Vector, ale powinieneś użyć ArrayList.

Z dokumentu API

Począwszy od platformy Java 2 v1.2, klasa ta została zmodernizowana w celu implementacji interfejsu List, co czyni go członkiem środowiska Java Collections Framework. W przeciwieństwie do nowych implementacji kolekcji Vector jest zsynchronizowany.

Justin
źródło
Listy, do których można uzyskać dostęp jako tablice? ArrayList nie jest bardzo krótką lub chwytliwą nazwą, co może być powodem, dla którego wektor jest używany gdzie indziej (np. STL).
opóźniony
6
@dhardy Lista z tablicą jako podstawową implementacją. Tam ArrayList, LinkedListitp, z których wszystkie implementują interfejs List, więc jeśli chcesz korzystać z Listmetody bez konieczności wiedzieć, co podstawowa realizacja rzeczywistości można po prostu wziąć Listjako parametr do metody, itp To samo dotyczy realizatorów Mapi tak dalej. Tymczasem C ++ ma std::arrayklasę, która jest po prostu szablonowym zamiennikiem macierzy długości statycznej typu C.
JAB
41

Oprócz już podanych odpowiedzi na temat korzystania z Vector, Vector ma również szereg metod dotyczących wyliczania i pobierania elementów, które są inne niż interfejs List, a programiści (szczególnie ci, którzy nauczyli się Javy przed 1.2) mogą z nich korzystać, jeśli są w kod. Chociaż wyliczenia są szybsze, nie sprawdzają, czy kolekcja została zmodyfikowana podczas iteracji, co może powodować problemy, a biorąc pod uwagę, że Vector może zostać wybrany do jego synchronizacji - z dostępnym dostępem z wielu wątków, sprawia to, że jest to szczególnie szkodliwy problem. Wykorzystanie tych metod powoduje również sprzężenie dużej ilości kodu z Vectorem, dzięki czemu nie będzie łatwo zastąpić go inną implementacją List.

Yishai
źródło
14

Możesz użyć metody synchronizedCollection / List , java.util.Collectionaby uzyskać kolekcję bezpieczną dla wątków z kolekcji innej niż bezpieczna dla wątków.

Brian Henk
źródło
2
dlaczego to jest lepsze niż wektor?
fjsj
8
Jak wspomniał Jon, Vector nie będzie działał tak dobrze, a ta metoda pozwala wybrać, kiedy dobrym pomysłem jest synchronizacja. Jest to całkowicie problem projektowy. Powinieneś używać ArrayList zamiast Vector, ponieważ powinieneś domyślnie uzyskiwać dostęp niezsynchronizowany.
Brian Henk,
Jak to odpowiada na pytanie?
Markiz Lorne
8

java.util.Stackdziedziczy narzut związany z synchronizacją java.util.Vector, co zwykle nie jest uzasadnione.

Jednak dziedziczy o wiele więcej. To java.util.Stack extends java.util.Vectorbłąd w projektowaniu obiektowym. Puryści zauważą, że oferuje również wiele metod poza operacjami tradycyjnie związanymi ze stosem (a mianowicie: push, pop, peek, size). Jest to również możliwe do zrobienia search, elementAt, setElementAt, remove, oraz wiele innych operacji o dostępie swobodnym. Zasadniczo to użytkownik nie powinien korzystać z operacji bez stosu Stack.

Z tych powodów wydajności i projektowania OOP JavaDocjava.util.Stack poleca ArrayDequejako naturalny zamiennik. (Deque to więcej niż stos, ale przynajmniej ogranicza się do manipulowania dwoma końcami, zamiast oferować losowy dostęp do wszystkiego.)

200_sukces
źródło