Java Notes
Complete guide to Java Vector — synchronized dynamic array, internal resizing, legacy status, comparison with ArrayList, thread safety analysis, and migration guide.
What is Vector?
java.util.Vector is a synchronized, resizable array implementation of the List interface. It was part of Java since JDK 1.0 (before the Collections Framework existed) and was later retrofitted to implement List.
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, SerializableVector is functionally identical to ArrayList, with two key differences:
- All methods are synchronized (thread-safe but slow)
- Different growth strategy (doubles capacity by default, vs ArrayList's 50% growth)
Synchronization — How It Works
Every public method in Vector is declared synchronized:
This means every method call acquires the intrinsic lock (monitor) on the Vector instance. While one thread is executing any synchronized method, all other threads must wait.
The Problem with Per-Method Synchronization
Vector<String> vector = new Vector<>();
// THIS IS NOT THREAD-SAFE despite individual method synchronization!
if (!vector.isEmpty()) { // Lock acquired, released
String first = vector.get(0); // Lock acquired — but another thread may have
// removed elements between isEmpty() and get()!
}
// CORRECT — explicit synchronization for compound operations
synchronized (vector) {
if (!vector.isEmpty()) {
String first = vector.get(0); // Safe — holding lock throughout
}
}Vector Methods
Standard List Operations
import java.util.*;
public class VectorDemo {
public static void main(String[] args) {
Vector<String> vector = new Vector<>();
// Adding elements
vector.add("Apple");
vector.add("Banana");
vector.add("Cherry");
vector.addElement("Date"); // Legacy method
vector.insertElementAt("Fig", 2); // Legacy method
System.out.println("Vector: " + vector);
System.out.println("Size: " + vector.size());
System.out.println("Capacity: " + vector.capacity());
// Accessing elements
System.out.println("get(0): " + vector.get(0));
System.out.println("firstElement(): " + vector.firstElement());
System.out.println("lastElement(): " + vector.lastElement());
System.out.println("elementAt(2): " + vector.elementAt(2));
// Removing elements
vector.remove("Banana");
vector.removeElementAt(0); // Legacy method
System.out.println("After removal: " + vector);
// Capacity management
vector.ensureCapacity(50); // Guarantee at least 50
System.out.println("Capacity after ensure: " + vector.capacity());
vector.trimToSize(); // Shrink to fit
System.out.println("Capacity after trim: " + vector.capacity());
}
}Vector: [Apple, Banana, Cherry, Date] First: Apple Last: Date Element at 2: Cherry Capacity: 10 Size: 4 After remove: [Apple, Cherry, Date] Contains Banana: false
Legacy Methods (from pre-Collections era)
| Legacy Method | Modern Equivalent |
|---|---|
addElement(E) | add(E) |
removeElement(Object) | remove(Object) |
removeElementAt(int) | remove(int) |
elementAt(int) | get(int) |
setElementAt(E, int) | set(int, E) |
insertElementAt(E, int) | add(int, E) |
firstElement() | get(0) |
lastElement() | get(size()-1) |
copyInto(Object[]) | toArray() |
elements() (Enumeration) | iterator() |
Time Complexity
| Operation | Time Complexity | Notes |
|---|---|---|
| ----------- | :-: | --- |
add(E e) | O(1) amortized | May resize O(n) rarely |
add(int index, E e) | O(n) | Shift elements right |
get(int index) | O(1) | Direct array access |
set(int index, E e) | O(1) | Direct array access |
remove(int index) | O(n) | Shift elements left |
remove(Object o) | O(n) | Search + shift |
contains(Object o) | O(n) | Linear search |
size() | O(1) | Stored field |
indexOf(Object o) | O(n) | Linear search |
Plus overhead: Every operation acquires and releases a monitor lock.
Vector vs ArrayList — Detailed Comparison
| Feature | Vector | ArrayList |
|---|---|---|
| Introduced | JDK 1.0 | JDK 1.2 |
| Synchronization | Yes (every method) | No |
| Thread-safe | Yes (basic) | No |
| Growth factor | 2x (doubles) | 1.5x (50% growth) |
| Performance | Slower (lock overhead) | Faster |
| Legacy methods | Yes (addElement, etc.) | No |
| Memory efficiency | Lower (aggressive growth) | Better |
| Null elements | Allowed | Allowed |
| Iterator | Fail-fast + Enumeration | Fail-fast only |
| Use in new code | ❌ No | ✅ Yes |
Performance Impact of Synchronization
When Vector's Synchronization Isn't Enough
// RACE CONDITION despite Vector being "thread-safe"
Vector<String> shared = new Vector<>();
shared.add("item");
// Thread 1:
if (shared.size() > 0) { // Check
String item = shared.get(0); // Use — BUT Thread 2 may have removed it!
}
// Thread 2:
if (shared.size() > 0) {
shared.remove(0); // Remove between Thread 1's check and use!
}
// SOLUTION: External synchronization
synchronized (shared) {
if (shared.size() > 0) {
String item = shared.get(0); // Safe
}
}Modern Alternatives to Vector
For Single-Threaded Code
// Just use ArrayList
List<String> list = new ArrayList<>();For Multi-Threaded Code
// Option 1: Collections.synchronizedList (same behavior as Vector)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// Option 2: CopyOnWriteArrayList (best for read-heavy workloads)
List<String> cowList = new CopyOnWriteArrayList<>();
// Option 3: Concurrent data structures
// Use ConcurrentHashMap, ConcurrentLinkedQueue, etc.Migration Guide
// BEFORE (legacy code):
Vector<String> items = new Vector<>();
items.addElement("data");
Enumeration<String> e = items.elements();
while (e.hasMoreElements()) {
process(e.nextElement());
}
// AFTER (modern code):
List<String> items = new ArrayList<>(); // or synchronizedList if needed
items.add("data");
for (String item : items) {
process(item);
}Enumeration vs Iterator
Vector supports both Enumeration (legacy) and Iterator (modern):
Vector<String> v = new Vector<>(Arrays.asList("A", "B", "C"));
// Legacy: Enumeration (no remove, not fail-fast)
Enumeration<String> e = v.elements();
while (e.hasMoreElements()) {
System.out.println(e.nextElement());
}
// Modern: Iterator (has remove, fail-fast)
Iterator<String> it = v.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.equals("B")) it.remove(); // Safe removal
}| Feature | Enumeration | Iterator |
|---|---|---|
| Methods | hasMoreElements(), nextElement() | hasNext(), next(), remove() |
| Removal | Not supported | Supported |
| Fail-fast | No | Yes |
| Introduced | JDK 1.0 | JDK 1.2 |
Common Mistakes
1. Using Vector in New Code
// WRONG — no reason to use Vector in single-threaded code
Vector<String> items = new Vector<>();
// CORRECT — use ArrayList
List<String> items = new ArrayList<>();2. Assuming Vector is Fully Thread-Safe
// WRONG — compound operation is NOT atomic
if (vector.contains(item)) {
vector.remove(item); // Another thread might have removed it!
}
// CORRECT — synchronize the compound operation
synchronized (vector) {
if (vector.contains(item)) {
vector.remove(item);
}
}3. Ignoring Capacity Growth Waste
// Vector doubles: after adding 1025 elements, capacity is 2048 (wastes 1023 slots)
// Better: set initial capacity if you know the size
Vector<String> v = new Vector<>(expectedSize);Interview Questions
Q1: What is the difference between Vector and ArrayList?
A: Vector is synchronized (thread-safe, slower), doubles in capacity, has legacy methods, and was in Java since 1.0. ArrayList is unsynchronized (faster), grows by 50%, and was introduced in Java 1.2.
Q2: Is Vector truly thread-safe?
A: Only for individual operations. Compound operations (check-then-act) are NOT atomic and require external synchronization.
Q3: What is the default capacity and growth strategy of Vector?
A: Default capacity is 10. When full, it doubles in size (unless capacityIncrement is set in the constructor).
Q4: Why is Vector considered legacy?
A: Because its per-method synchronization provides a false sense of thread safety while adding overhead. Collections.synchronizedList() or CopyOnWriteArrayList are better alternatives.
Q5: Can Vector hold null values?
A: Yes. Both Vector and ArrayList allow null elements.
Q6: What is the difference between Enumeration and Iterator?
A: Enumeration is legacy (no remove, not fail-fast). Iterator is modern (supports remove, fail-fast on concurrent modification).
Q7: How would you convert legacy Vector code to modern Java?
A: Replace Vector with ArrayList (single-threaded) or Collections.synchronizedList(new ArrayList<>()) (multi-threaded). Replace Enumeration with Iterator. Replace legacy methods with standard List methods.
Summary
| Aspect | Vector |
|---|---|
| Status | Legacy — do NOT use in new code |
| Replace with | ArrayList (single-thread) or CopyOnWriteArrayList (multi-thread) |
| Internal structure | Synchronized dynamic array |
| Growth | Doubles (2x) |
| Thread-safety | Per-method only (not compound) |
| Null support | Yes |
| Key takeaway | Understand for interview, never use in practice |
Q8: When would you still use Vector in modern Java?
A: Almost never. The only scenario is maintaining legacy code that depends on Vector's API. For thread-safety, use Collections.synchronizedList(new ArrayList<>()) or CopyOnWriteArrayList. For non-threaded code, use ArrayList. Vector's method-level synchronization is too coarse-grained for most concurrent patterns.
Q9: How does Vector's capacity growth differ from ArrayList?
A: Vector doubles its capacity when full (2x growth), unless capacityIncrement is specified in the constructor. ArrayList grows by 50% (oldCapacity + oldCapacity >> 1). This means Vector wastes more memory after growth but resizes less frequently.
Q10: What is the difference between Enumeration and Iterator in context of Vector?
A: elements() returns Enumeration (legacy, no remove support, not fail-fast). iterator() returns Iterator (modern, supports remove, fail-fast). Enumeration was the pre-Collections way to traverse; Iterator is the standard since Java 1.2. Always prefer Iterator.
Q11: Why is Vector's synchronization considered inefficient?
A: Every individual method call acquires and releases the lock, even simple reads like get(). If you need to perform multiple operations atomically (check-then-act), you still need external synchronization. This makes Vector's built-in sync both costly (per-call overhead) and insufficient (no compound atomicity).
Q12: Can you use Vector with Java Streams?
A: Yes, Vector extends AbstractList which implements Collection, so you can call vector.stream() and vector.parallelStream(). However, the synchronized nature doesn't help with parallel streams — use ArrayList or arrays as stream sources for better performance.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Vector in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, collections, framework, list
Related Java Master Course Topics