Why is Java Vector considered a legacy class, obsolete or deprecated?
Isn't its use valid when working with concurrency?
And if I don't want to manually synchronize objects and just want to use a thread-safe collection without needing to make fresh copies of the underlying array (as CopyOnWriteArrayList
does), then is it fine to use Vector
?
What about Stack
, which is a subclass of Vector
, what should I use instead of it?
Vector
synchronizes on each individual operation. That's almost never what you want to do.
Generally you want to synchronize a whole sequence of operations. Synchronizing individual operations is both less safe (if you iterate over a Vector
, for instance, you still need to take out a lock to avoid anyone else changing the collection at the same time, which would cause a ConcurrentModificationException
in the iterating thread) but also slower (why take out a lock repeatedly when once will be enough)?
Of course, it also has the overhead of locking even when you don't need to.
Basically, it's a very flawed approach to synchronization in most situations. As Mr Brian Henk pointed out, you can decorate a collection using the calls such as Collections.synchronizedList
- the fact that Vector
combines both the "resized array" collection implementation with the "synchronize every operation" bit is another example of poor design; the decoration approach gives cleaner separation of concerns.
As for a Stack
equivalent - I'd look at Deque
/ArrayDeque
to start with.
Vector was part of 1.0 -- the original implementation had two drawbacks:
1. Naming: vectors are really just lists which can be accessed as arrays, so it should have been called ArrayList
(which is the Java 1.2 Collections replacement for Vector
).
2. Concurrency: All of the get()
, set()
methods are synchronized
, so you can't have fine grained control over synchronization.
There is not much difference between ArrayList
and Vector
, but you should use ArrayList
.
From the API doc.
As of the Java 2 platform v1.2, this class was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized.
ArrayList
, LinkedList
, etc., all of which implement the interface List
, so if you want to utilize the List
methods without having to know what the underlying implementation actually is you can just take a List
as a parameter to methods, etc. The same applies for implementers of Map
and so on. Meanwhile, C++ does have a std::array
class, which is just a template-based replacement for C-style static length arrays.
Besides the already stated answers about using Vector, Vector also has a bunch of methods around enumeration and element retrieval which are different than the List interface, and developers (especially those who learned Java before 1.2) can tend to use them if they are in the code. Although Enumerations are faster, they don't check if the collection was modified during iteration, which can cause issues, and given that Vector might be chosen for its syncronization - with the attendant access from multiple threads, this makes it a particularly pernicious problem. Usage of these methods also couples a lot of code to Vector, such that it won't be easy to replace it with a different List implementation.
You can use the synchronizedCollection/List method in java.util.Collection
to get a thread-safe collection from a non-thread-safe one.
java.util.Stack
inherits the synchronization overhead of java.util.Vector
, which is usually not justified.
It inherits a lot more than that, though. The fact that java.util.Stack extends java.util.Vector
is a mistake in object-oriented design. Purists will note that it also offers a lot of methods beyond the operations traditionally associated with a stack (namely: push, pop, peek, size). It's also possible to do search
, elementAt
, setElementAt
, remove
, and many other random-access operations. It's basically up to the user to refrain from using the non-stack operations of Stack
.
For these performance and OOP design reasons, the JavaDoc for java.util.Stack
recommends ArrayDeque
as the natural replacement. (A deque is more than a stack, but at least it's restricted to manipulating the two ends, rather than offering random access to everything.)
Success story sharing