☕ Java

Java Vector Class

A complete guide to the Java Vector class — thread safety, dynamic resizing, capacity management, Vector vs ArrayList, Enumeration, ListIterator, synchronized collections, and best practices with real-world examples.

📅

Last Updated

March 2026

⏱️

Read Time

17 min

🎯

Level

Beginner to Intermediate

What is the Java Vector Class?

The Vector class in Java is a part of the java.util package and implements a dynamic (resizable) array of objects. Unlike a plain Java array whose size is fixed at creation time, a Vector automatically grows and shrinks as elements are added or removed. It can hold elements of any type (including null) and maintains insertion order.

Vector is one of Java's legacy collection classes, available since Java 1.0 — long before the Collections Framework was introduced in Java 1.2. When the Collections Framework arrived, Vector was retrofitted to implement the List interface, making it compatible with the modern framework. Its most distinctive feature is that all its methods are synchronized, making it inherently thread-safe.

Think of a Vector as a thread-safe, self-expanding shelf. You can add as many books (elements) as you like — the shelf expands automatically when full. And because it is synchronized, two people (threads) can safely add or remove books simultaneously without corrupting the shelf's state.

Vector Syntax and Constructors

The Vector class provides four constructors to control initial capacity and growth behavior:

☕ JavaVector Constructors
import java.util.Vector;

// 1. Default constructor — initial capacity 10, doubles when full
Vector<String> v1 = new Vector<>();

// 2. Constructor with initial capacity
Vector<Integer> v2 = new Vector<>(20);

// 3. Constructor with initial capacity AND capacity increment
//    grows by 5 each time instead of doubling
Vector<Double> v3 = new Vector<>(10, 5);

// 4. Constructor from existing Collection
java.util.List<String> list = java.util.Arrays.asList("A", "B", "C");
Vector<String> v4 = new Vector<>(list);
☕ JavaVector — Basic Operations
import java.util.Vector;

public class VectorBasics {
    public static void main(String[] args) {

        Vector<String> cities = new Vector<>();

        // Adding elements
        cities.add("Mumbai");
        cities.add("Delhi");
        cities.add("Bengaluru");
        cities.addElement("Chennai");   // legacy method

        System.out.println("Cities: " + cities);
        System.out.println("Size: " + cities.size());
        System.out.println("Capacity: " + cities.capacity());

        // Accessing elements
        System.out.println("First: " + cities.get(0));
        System.out.println("Last: " + cities.lastElement());

        // Removing elements
        cities.remove("Delhi");
        System.out.println("After removal: " + cities);
    }
}

Output

Cities: [Mumbai, Delhi, Bengaluru, Chennai] Size: 4 Capacity: 10 First: Mumbai Last: Chennai After removal: [Mumbai, Bengaluru, Chennai]

Why Use the Vector Class?

While Vector is considered a legacy class, understanding it is essential for Java developers for several reasons:

  • 🔒 Built-in Thread Safety — Every method in Vector is synchronized, making it safe to use in multi-threaded environments without any additional synchronization code. This was critical in Java 1.0 before java.util.concurrent existed.

  • 📈 Dynamic Resizing — Vector automatically grows when capacity is exhausted. Unlike fixed-size arrays, you never need to pre-know the exact number of elements.

  • 🏛️ Legacy Codebase Compatibility — Millions of lines of Java enterprise code use Vector. Reading, maintaining, and modernizing such code requires deep familiarity with Vector's behavior.

  • 📋 List Interface Compliance — Vector fully implements the java.util.List interface, so it can be passed anywhere a List is expected — making it interoperable with the modern Collections Framework.

  • 📜 Enumeration Support — Vector is the only modern collection that natively supports the legacy Enumeration interface, used in old Java APIs like Properties and Hashtable.

  • 🎓 Foundation for Learning — Understanding Vector's design (and its trade-offs) teaches the core principles behind thread-safe collections, capacity management, and why modern alternatives like CopyOnWriteArrayList were designed.

Vector vs ArrayList vs LinkedList

Choosing between Vector, ArrayList, and LinkedList is one of the most common decisions in Java. Here is a definitive comparison:

FeatureVectorArrayListLinkedList
IntroducedJava 1.0 (legacy)Java 1.2Java 1.2
ImplementsList, RandomAccess, CloneableList, RandomAccess, CloneableList, Deque, Cloneable
Thread-safe?✅ Yes — all methods synchronized❌ No❌ No
Performance (single-thread)Slower — due to synchronization overheadFaster — no lock overheadModerate — O(1) insert/delete at ends
Random access (get/set)O(1) — fastO(1) — fastO(n) — slow
Insert/Delete at middleO(n) — slow (shift elements)O(n) — slow (shift elements)O(1) — fast (pointer update)
Memory usageSlightly higher (lock objects)ModerateHigher (node pointers per element)
Capacity growthDoubles (or by capacityIncrement)Grows by ~50%No pre-allocation (linked nodes)
Allows null?✅ Yes✅ Yes✅ Yes
Allows duplicates?✅ Yes✅ Yes✅ Yes
Maintains order?✅ Insertion order✅ Insertion order✅ Insertion order
Use whenLegacy code or simple thread safety neededSingle-threaded, frequent readsFrequent insert/delete at both ends
Modern alternativeCopyOnWriteArrayList, Collections.synchronizedList()ArrayDeque (for queue usage)

Rule of thumb: In new single-threaded code, always prefer ArrayList. For thread-safe scenarios, use Collections.synchronizedList(new ArrayList<>()) or CopyOnWriteArrayList. Use Vector only when maintaining or extending legacy Java code.

Vector in the Java Collections Hierarchy

Understanding where Vector sits in Java's Collections hierarchy helps clarify which interfaces it satisfies and which methods it inherits.

java.lang.Object
Root of all Java classes
java.util.AbstractCollection<E>
Provides skeletal implementations of Collection methods
java.util.AbstractList<E>
Implements List based on random-access data store
java.util.Vector<E>
Implements: List<E>, RandomAccess, Cloneable, SerializableSubclass: Stack<E>
Key Interfaces satisfied by Vector
Collection<E>Iterable<E>List<E>RandomAccessCloneableSerializable

Architecture Diagram

Note: Java's Stack class extends Vector, making Vector the parent of Stack. This is why Stack in Java also inherits synchronization. However, both Vector and Stack are considered legacy — prefer ArrayDeque for stack behavior in modern Java.

Important Vector Methods

Vector provides both modern List interface methods and legacy methods from its pre-Collections-Framework days. Knowing both is essential for working with legacy codebases.

MethodDescriptionType
add(E e)Appends element to endModern (List)
add(int index, E e)Inserts element at specified indexModern (List)
addElement(E obj)Appends element — legacy equivalent of add()Legacy
get(int index)Returns element at specified indexModern (List)
elementAt(int index)Returns element at index — legacy equivalent of get()Legacy
set(int index, E e)Replaces element at specified indexModern (List)
setElementAt(E obj, int index)Sets element at index — legacy equivalent of set()Legacy
remove(int index)Removes element at specified indexModern (List)
removeElementAt(int index)Removes element at index — legacy methodLegacy
remove(Object o)Removes first occurrence of specified elementModern (List)
removeElement(Object obj)Removes first occurrence — legacy methodLegacy
removeAllElements()Removes all elements, sets size to 0Legacy
size()Returns current number of elementsModern (List)
capacity()Returns current allocated capacityVector-specific
isEmpty()Returns true if size is 0Modern (Collection)
contains(Object o)Returns true if element is presentModern (Collection)
indexOf(Object o)Returns index of first occurrence, -1 if absentModern (List)
lastIndexOf(Object o)Returns index of last occurrence, -1 if absentModern (List)
firstElement()Returns first elementLegacy
lastElement()Returns last elementLegacy
clear()Removes all elements (modern)Modern (Collection)
trimToSize()Reduces capacity to current size — saves memoryVector-specific
ensureCapacity(int min)Ensures capacity is at least min valueVector-specific
copyInto(Object[] arr)Copies elements into given arrayLegacy
elements()Returns Enumeration over elementsLegacy
iterator()Returns Iterator over elementsModern (Collection)
listIterator()Returns ListIterator (bidirectional)Modern (List)
subList(int from, int to)Returns a view of portion of the listModern (List)
toArray()Returns Object array of all elementsModern (Collection)
Collections.sort(vector)Sorts the Vector (external utility)Modern (utility)

Capacity and Increment Management in Vector

One of Vector's most important — and often misunderstood — features is how it manages capacity. Unlike arrays where size is fixed, Vector maintains two separate concepts: size (number of actual elements) and capacity (total allocated storage).

  • 📦 Default Capacity — When created with new Vector<>(), the initial capacity is 10. This means Vector pre-allocates space for 10 elements even if you add only 2.

  • 📈 Doubling Growth — When no capacityIncrement is set, Vector doubles its capacity each time the size exceeds the capacity. So: 10 → 20 → 40 → 80 → ...

  • 🔢 Fixed Increment Growth — If you specify a capacityIncrement (e.g., new Vector<>(10, 5)), the capacity grows by exactly that fixed amount each time: 10 → 15 → 20 → 25 → ...

  • ✂️ trimToSize() — Calling trimToSize() reduces the capacity to match the current size, freeing unused memory. Useful after bulk-loading data that will not grow further.

  • 🔒 ensureCapacity(n) — Pre-allocates capacity to at least n elements. Useful when you know the approximate final size upfront — avoids multiple resize operations.

☕ JavaCapacity Management Demo
import java.util.Vector;

public class CapacityDemo {
    public static void main(String[] args) {

        // Default: capacity 10, doubles on overflow
        Vector<Integer> v = new Vector<>();
        System.out.println("Initial capacity: " + v.capacity());  // 10

        // Add 11 elements — triggers resize
        for (int i = 1; i <= 11; i++) {
            v.add(i);
        }
        System.out.println("Capacity after 11 adds: " + v.capacity()); // 20
        System.out.println("Size: " + v.size());                       // 11

        // trimToSize — frees unused space
        v.trimToSize();
        System.out.println("Capacity after trimToSize: " + v.capacity()); // 11

        // Fixed increment: capacity 5, grows by 3 each time
        Vector<String> v2 = new Vector<>(5, 3);
        System.out.println("\nv2 initial capacity: " + v2.capacity()); // 5
        for (int i = 0; i < 6; i++) v2.add("item" + i);
        System.out.println("v2 capacity after 6 adds: " + v2.capacity()); // 8
    }
}

Output

Initial capacity: 10 Capacity after 11 adds: 20 Size: 11 Capacity after trimToSize: 11 v2 initial capacity: 5 v2 capacity after 6 adds: 8

Thread Safety in Vector

Vector achieves thread safety by declaring all its public methods as synchronized. This means the JVM acquires an intrinsic lock (monitor) on the Vector object before executing any method, and releases it afterward. Only one thread can execute any Vector method at a time.

☕ JavaVector Thread Safety Demo
import java.util.Vector;

public class ThreadSafetyDemo {

    public static void main(String[] args) throws InterruptedException {
        Vector<Integer> sharedVector = new Vector<>();

        // Thread 1: adds even numbers
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                sharedVector.add(i * 2);
                System.out.println(Thread.currentThread().getName()
                    + " added: " + (i * 2));
            }
        }, "Thread-Even");

        // Thread 2: adds odd numbers
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                sharedVector.add(i * 2 + 1);
                System.out.println(Thread.currentThread().getName()
                    + " added: " + (i * 2 + 1));
            }
        }, "Thread-Odd");

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        // No ConcurrentModificationException — Vector is thread-safe
        System.out.println("\nFinal Vector (10 elements): " + sharedVector);
        System.out.println("Final size: " + sharedVector.size());
    }
}

Important caveat: Even though individual Vector methods are synchronized, compound operations (check-then-act patterns) are NOT atomically safe. For example, if (!v.isEmpty()) v.remove(0); is NOT thread-safe even with Vector — another thread could remove the last element between the check and the remove. For compound atomic operations, use explicit synchronization or java.util.concurrent classes.

Vector Resize Flow — Flowchart

The flowchart below illustrates exactly how Vector decides whether to resize and by how much when a new element is added.

➕ add(element)called on Vector
❓ Is size < capacity?check internal array
Yes
✅ Insert directlyNo resize needed
❓ capacityIncrement > 0?check constructor arg
Yes
📈 Grow by capacityIncrementnewCapacity = old + increment
📈 Double the capacitynewCapacity = old × 2
🔄 Allocate new arraycopy old elements
✅ Insert elementinto expanded array

Code Execution Flow — from source to output

Enumeration and ListIterator in Vector

Vector supports three ways to traverse its elements: the legacy Enumeration, the modern Iterator, and the bidirectional ListIterator. Understanding each is important when working with legacy APIs.

☕ JavaEnumeration vs Iterator vs ListIterator
import java.util.*;

public class VectorTraversal {
    public static void main(String[] args) {

        Vector<String> fruits = new Vector<>();
        fruits.add("Mango");
        fruits.add("Banana");
        fruits.add("Papaya");
        fruits.add("Guava");

        // --- 1. Legacy Enumeration (Java 1.0) ---
        System.out.println("--- Enumeration ---");
        Enumeration<String> en = fruits.elements();
        while (en.hasMoreElements()) {
            System.out.println(en.nextElement());
        }

        // --- 2. Modern Iterator ---
        System.out.println("\n--- Iterator ---");
        Iterator<String> it = fruits.iterator();
        while (it.hasNext()) {
            String fruit = it.next();
            if (fruit.equals("Banana")) {
                it.remove();  // safe removal during iteration
            } else {
                System.out.println(fruit);
            }
        }

        // --- 3. ListIterator (bidirectional) ---
        System.out.println("\n--- ListIterator (reverse) ---");
        ListIterator<String> li = fruits.listIterator(fruits.size());
        while (li.hasPrevious()) {
            System.out.println(li.previous());
        }
    }
}

Output

--- Enumeration --- Mango Banana Papaya Guava --- Iterator --- Mango Papaya Guava --- ListIterator (reverse) --- Guava Papaya Mango

Key difference: Enumeration is read-only and cannot remove elements. Iterator adds safe removal via it.remove(). ListIterator further adds add(), set(), and bidirectional traversal. In modern code, always prefer Iterator or ListIterator over Enumeration.

Best Practices for Using Vector

Knowing when and how to use Vector correctly separates professional Java developers from beginners. Here are the industry-standard best practices:

  • ✅ 1. Prefer ArrayList for New Single-Threaded Code — In new non-threaded code, ArrayList always outperforms Vector due to lack of synchronization overhead. Never use Vector by default just because it exists.

  • ✅ 2. Use Collections.synchronizedList() for Flexible Thread Safety — For modern synchronized list behavior, Collections.synchronizedList(new ArrayList<>()) gives you thread safety on top of ArrayList without the legacy baggage of Vector.

  • ✅ 3. Prefer CopyOnWriteArrayList for Read-Heavy Concurrent Scenarios — When reads vastly outnumber writes, CopyOnWriteArrayList from java.util.concurrent is far more performant than Vector since reads are lock-free.

  • ✅ 4. Set Appropriate Initial Capacity — If you know the approximate final size, initialize with new Vector<>(expectedSize) to avoid multiple internal array copies. Avoids performance degradation from repeated resizing.

  • ✅ 5. Use trimToSize() After Bulk Loading — After adding a large batch of elements that won't grow further, call trimToSize() to free unused allocated memory.

  • ✅ 6. Use Iterator, Not Enumeration, for New Code — Enumeration is a relic from Java 1.0. Use Iterator or enhanced for-loop for traversal. Only use Enumeration when interacting with old APIs that require it (e.g., Properties.keys()).

  • ❌ 7. Never Rely on Vector for Atomic Compound Operations — Individual Vector method calls are synchronized, but compound operations (check-then-act) are not. Use explicit synchronized blocks or java.util.concurrent.atomic classes for atomicity.

  • ❌ 8. Do Not Mix Legacy and Modern Method Styles — Mixing addElement() with add() and elementAt() with get() in the same codebase creates confusion. Pick one style — modern List methods are preferred for readability and IDE support.

☕ JavaBest Practice — Preferred Alternatives to Vector
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class VectorAlternatives {
    public static void main(String[] args) {

        // ✅ Single-threaded — use ArrayList
        List<String> singleThreadList = new ArrayList<>();
        singleThreadList.add("Item A");

        // ✅ Multi-threaded, general — use synchronizedList
        List<String> syncList = Collections.synchronizedList(new ArrayList<>());
        syncList.add("Safe Item");

        // ✅ Multi-threaded, read-heavy — use CopyOnWriteArrayList
        List<String> cowList = new CopyOnWriteArrayList<>();
        cowList.add("Config Value 1");
        cowList.add("Config Value 2");

        // ✅ Legacy code compatibility — Vector is acceptable here
        Vector<String> legacyVector = new Vector<>();
        legacyVector.add("Legacy compatible");

        System.out.println("ArrayList: " + singleThreadList);
        System.out.println("SynchronizedList: " + syncList);
        System.out.println("CopyOnWriteArrayList: " + cowList);
        System.out.println("Vector: " + legacyVector);
    }
}

Real-World Code Examples

Example 1 — Task Queue Using Vector (Multi-threaded)

☕ JavaThread-Safe Task Queue with Vector
import java.util.Vector;

public class TaskQueue {

    private final Vector<String> queue = new Vector<>();

    public void enqueue(String task) {
        queue.add(task);
        System.out.println(Thread.currentThread().getName()
            + " enqueued: " + task + " | Queue size: " + queue.size());
    }

    public String dequeue() {
        if (!queue.isEmpty()) {
            String task = queue.remove(0);
            System.out.println(Thread.currentThread().getName()
                + " dequeued: " + task);
            return task;
        }
        return null;
    }

    public static void main(String[] args) throws InterruptedException {
        TaskQueue tq = new TaskQueue();

        Thread producer = new Thread(() -> {
            tq.enqueue("Send Email");
            tq.enqueue("Generate Report");
            tq.enqueue("Backup Database");
        }, "Producer");

        Thread consumer = new Thread(() -> {
            try { Thread.sleep(50); } catch (InterruptedException ignored) {}
            tq.dequeue();
            tq.dequeue();
        }, "Consumer");

        producer.start();
        consumer.start();
        producer.join();
        consumer.join();

        System.out.println("Remaining tasks: " + tq.queue);
    }
}

Output

Producer enqueued: Send Email | Queue size: 1 Producer enqueued: Generate Report | Queue size: 2 Producer enqueued: Backup Database | Queue size: 3 Consumer dequeued: Send Email Consumer dequeued: Generate Report Remaining tasks: [Backup Database]

Example 2 — Student Score Manager

☕ JavaStudent Score Manager with Vector
import java.util.*;

public class ScoreManager {

    static Vector<Integer> scores = new Vector<>(5, 5);

    public static void addScore(int score) {
        scores.add(score);
    }

    public static double getAverage() {
        int sum = 0;
        for (int s : scores) sum += s;
        return scores.isEmpty() ? 0 : (double) sum / scores.size();
    }

    public static int getHighest() {
        return Collections.max(scores);
    }

    public static int getLowest() {
        return Collections.min(scores);
    }

    public static void main(String[] args) {
        int[] raw = {88, 74, 95, 61, 83, 79, 92, 55};
        for (int s : raw) addScore(s);

        System.out.println("Scores: " + scores);
        System.out.println("Count: " + scores.size());
        System.out.println("Capacity: " + scores.capacity());
        System.out.printf ("Average: %.2f%n", getAverage());
        System.out.println("Highest: " + getHighest());
        System.out.println("Lowest: "  + getLowest());

        Collections.sort(scores);
        System.out.println("Sorted: " + scores);
    }
}

Output

Scores: [88, 74, 95, 61, 83, 79, 92, 55] Count: 8 Capacity: 10 Average: 78.38 Highest: 95 Lowest: 55 Sorted: [55, 61, 74, 79, 83, 88, 92, 95]

Practice This Code — Live Editor

Advantages and Disadvantages of Vector

Like every data structure, Vector has clear strengths and weaknesses. Knowing both helps you make the right choice for the right scenario.

✅ Advantages
Built-in Thread SafetyAll Vector methods are synchronized — safe to use from multiple threads out of the box, with zero additional synchronization code required.
Dynamic ResizingAutomatically grows when elements exceed capacity. No need to manually manage array size or copy data — Vector handles it transparently.
Controllable GrowthThe capacityIncrement constructor parameter lets you control exactly how the Vector grows, which can reduce memory waste or avoid thrashing in memory-sensitive scenarios.
Full List InterfaceImplements java.util.List completely — usable anywhere a List is expected, fully compatible with Collections utility methods (sort, shuffle, binarySearch, etc.).
Enumeration SupportProvides elements() which returns an Enumeration — essential when working with legacy APIs that expect Enumeration (e.g., java.util.Properties, javax.servlet APIs).
Random AccessImplements RandomAccess marker interface — O(1) get() and set() operations, same as ArrayList. Efficient for index-based access.
❌ Disadvantages
Performance OverheadEvery method acquires a synchronized lock, even in single-threaded use. This makes Vector noticeably slower than ArrayList for single-threaded workloads — often 30-50% slower in benchmarks.
Legacy DesignRetrofitted into the Collections Framework rather than designed for it. Contains redundant legacy methods (addElement, elementAt, removeAllElements) alongside their modern equivalents, creating API clutter.
Over-SynchronizationSynchronizing every method individually creates unnecessarily high locking overhead. For compound operations, external synchronization is still needed — giving you all the cost of synchronization with incomplete safety guarantees.
Memory Doubling Can Waste SpaceDefault doubling strategy can significantly over-allocate memory for large collections. A Vector that grows to hold 1025 elements has capacity 2048 — 1023 unused slots.
Considered Obsolete in New CodeJava documentation and community consensus discourage Vector in new code. CopyOnWriteArrayList and Collections.synchronizedList() cover its use cases better with cleaner semantics.

Java Vector — Interview Questions

These are the most frequently asked interview questions on the Java Vector class for Java developer and backend engineer positions.

Practice Questions — Test Your Knowledge

Test your understanding of the Vector class with these practice questions. Attempt each one before revealing the answer.

1. You create Vector<Integer> v = new Vector<>(). You add 15 elements one by one. What is the capacity after adding the 11th element?

Easy

2. What is the output? Vector<String> v = new Vector<>(4, 3); for (int i = 0; i < 5; i++) v.add("x"); System.out.println(v.capacity());

Easy

3. Why is this compound Vector operation NOT thread-safe, even though Vector is synchronized? if (!v.isEmpty()) { v.remove(0); }

Medium

4. You have a Vector with 1000 elements. You call trimToSize(). Then you add one more element. What happens?

Medium

5. Can you use a for-each loop on a Vector? What happens if you remove an element inside the loop?

Medium

6. You need a thread-safe List for a scenario where there are 100 reads per second but only 2 writes per hour. Which is better: Vector, Collections.synchronizedList, or CopyOnWriteArrayList?

Hard

7. What is the output? Vector<Integer> v = new Vector<>(Arrays.asList(5, 3, 8, 1, 9)); Collections.sort(v); System.out.println(v.firstElement() + " " + v.lastElement());

Easy

8. Both Vector and Stack are considered legacy classes. What are the modern replacements recommended for their respective use cases?

Hard

Conclusion — Mastering Java Vector

The Vector class is a window into Java's history — it was the original solution for thread-safe, dynamic collections when Java first launched in 1995. Understanding Vector deeply means understanding why modern Java evolved the way it did: why ArrayList was created for performance, why CopyOnWriteArrayList was designed for concurrent reads, and why the Collections Framework standardized a clean interface hierarchy.

In production Java today, Vector rarely appears in new code — but it remains alive in millions of legacy enterprise systems, in the JDK's own Stack class, and in APIs that predate Java 1.2. A complete Java developer is fluent in both the modern idioms and the legacy landscape.

ScenarioRecommended Choice
Single-threaded list operations✅ ArrayList — fastest, no overhead
Thread-safe list, general purpose✅ Collections.synchronizedList(new ArrayList<>())
Thread-safe list, 90%+ reads✅ CopyOnWriteArrayList — lock-free reads
Maintaining legacy code using Vector✅ Keep Vector — refactoring may introduce bugs
Need Enumeration interface support✅ Vector.elements() — only List to support Enumeration natively
LIFO stack behavior✅ ArrayDeque — faster than java.util.Stack
Memory-sensitive with known max size✅ ArrayList with explicit initialCapacity

Your next steps: explore CopyOnWriteArrayList and ConcurrentLinkedQueue in java.util.concurrent, study Collections.synchronizedList() internals, and understand how Java 21's Virtual Threads (Project Loom) change the calculus for synchronized collections in high-throughput applications.

Remember: Vector is thread-safe but legacy. ArrayList is fast but single-threaded. CopyOnWriteArrayList is modern, concurrent, and read-optimized. Pick the right tool for your context, and your Java collections code will be correct, performant, and professional. ☕

Frequently Asked Questions (FAQ)