Почему класс Java Vector (и Stack) считается устаревшим или устаревшим?


677

Почему Java Vector считается устаревшим классом, устаревшим или устаревшим?

Разве его использование не допустимо при работе с параллелизмом?

И если я не хочу вручную синхронизировать объекты и просто хочу использовать потокобезопасную коллекцию без необходимости делать свежие копии базового массива (как это CopyOnWriteArrayListделается), то хорошо ли это использовать Vector?

Как насчет того Stack, что является подклассом Vector, что я должен использовать вместо него?


Они устарели, но не устарели.
Маркиз Лорн

Ответы:


655

Vectorсинхронизируется на каждой отдельной операции. Это почти никогда не то, что вы хотите сделать.

Как правило, вы хотите синхронизировать всю последовательность операций. Синхронизация отдельных операций и менее безопасна (например, если вы выполняете итерацию по a Vector, вам все равно нужно снять блокировку, чтобы никто не изменил коллекцию в одно и то же время, что могло бы вызвать a ConcurrentModificationExceptionв итерирующем потоке), но также и медленнее ( зачем вынимать блокировку повторно, когда одного раза будет достаточно)?

Конечно, он также имеет накладные расходы на блокировку, даже когда вам это не нужно.

По сути, это очень некорректный подход к синхронизации в большинстве ситуаций. Как отметил г-н Брайан Хенк , вы можете декорировать коллекцию, используя такие вызовы, как Collections.synchronizedList- тот факт, что Vectorкомбинация реализации коллекции «массив с измененным размером» и бита «синхронизировать каждую операцию» является еще одним примером плохого дизайна; декоративный подход дает более четкое разделение проблем.

Что касается Stackэквивалента - я бы посмотрел на Deque/ ArrayDequeдля начала.


108
«Как правило, вы хотите синхронизировать всю последовательность операций». - В этом все дело! Спасибо!
fjsj

7
в какой версии Java устаревший вектор (в настоящее время я использовал Java7). Но я никогда не вижу как устаревший? Пока,
кстати,

17
@Samir: Официально это не рекомендуется, просто ArrayList, как правило, предпочтительнее.
Джон Скит

26
@ Самир: Нет, я не буду пытаться предсказывать будущее.
Джон Скит

5
просто гр8. вектор не считается устаревшим, это устаревший класс. Должно быть различие между устаревшим и устаревшим
классом,

82

Vector был частью 1.0 - оригинальная реализация имела два недостатка:

1. Наименование: векторы на самом деле представляют собой просто списки, к которым можно обращаться как к массивам, поэтому их следует вызывать ArrayList(что является заменой коллекций Java 1.2 Vector).

2. Параллельность: Все из get(), set()методы synchronized, так что вы не можете иметь мелкозернистый контроль над синхронизацией.

Нет большой разницы между ArrayListи Vector, но вы должны использовать ArrayList.

Из API док.

Что касается платформы Java 2 v1.2, этот класс был модифицирован для реализации интерфейса List, что сделало его членом Java Collections Framework. В отличие от новых реализаций коллекции, Vector синхронизирован.


Списки, к которым можно обращаться как к массивам? ArrayList - это не очень короткое или броское имя, поэтому, возможно, вектор используется в другом месте (например, STL).
Дарди,

6
@dhardy Список с массивом в качестве базовой реализации. Там же ArrayList, LinkedListи т.д., все из которых реализует интерфейс List, так что если вы хотите использовать Listметоды , не зная , что основная реализация на самом деле вы можете просто взять в Listкачестве параметра методов и т.д. То же самое относится к реализаторам Mapи так далее. Между тем, в C ++ есть std::arrayкласс, который является просто заменой массивов статической длины в стиле C на основе шаблонов.
JAB

41

Помимо уже заявленных ответов об использовании Vector, в Vector также есть несколько методов для перечисления и извлечения элементов, которые отличаются от интерфейса List, и разработчики (особенно те, кто изучал Java до 1.2) могут использовать их, если они находятся в код. Несмотря на то, что перечисления выполняются быстрее, они не проверяют, была ли коллекция изменена во время итерации, что может вызвать проблемы, и учитывая, что Vector может быть выбран для его синхронизации - с помощью сопутствующего доступа из нескольких потоков, это делает ее особенно пагубной проблемой. Использование этих методов также связывает большую часть кода с Vector, так что будет нелегко заменить его другой реализацией List.


14

Вы можете использовать synchronizedCollection / List метод в java.util.Collectionполучить потокобезопасную коллекцию из не поточно-один.


2
почему это лучше, чем вектор?
fjsj

8
Как упоминал Джон, Vector не будет работать так же хорошо, и этот метод позволяет вам выбрать, когда стоит выполнить синхронизацию. Это полностью проблема дизайна. Вы должны использовать ArrayList поверх Vector, потому что вы должны по умолчанию использовать несинхронизированный доступ.
Брайан Хенк

Как это отвечает на вопрос?
Маркиз Лорн

8

java.util.Stackнаследует издержки синхронизации java.util.Vector, что обычно не оправдано.

Хотя он наследует намного больше, чем это. Дело в том, что java.util.Stack extends java.util.Vectorэто ошибка в объектно-ориентированном дизайне. Пуристы заметят, что он также предлагает множество методов помимо операций, традиционно связанных со стеком (а именно: push, pop, peek, size). Это также можно сделать search, elementAt, setElementAt, remove, и многие другие операции с произвольным доступом. Это в основном зависит от пользователя, чтобы воздерживаться от использования не-стек операций Stack.

По этим причинам производительности и дизайна ООП JavaDocjava.util.Stack рекомендует ArrayDequeв качестве естественной замены. (Deque - это больше, чем стек, но, по крайней мере, он ограничен манипулированием двумя концами, а не предлагает произвольный доступ ко всему.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.