Java List Interface Explained: ArrayList, LinkedList, Stack & Vector
As a 2nd-year Mechanical Engineering student making the leap into Software Development, the Java Collections Framework initially felt like walking into a massive factory where every machine looked exactly the same. Why are there so many classes? Why do I need four different ways just to store a simple list of items? In mechanical design, you don’t use a heavy-duty bolt where a quick rivet will do. Software is no different.
If you’ve ever felt overwhelmed trying to choose between ArrayList, LinkedList, Stack, and Vector, you aren’t alone. This article strips away the confusing jargon. We will break down the Java List interface simply, look at the actual code, and map each class to its real-world Data Structures and Algorithms (DSA) use cases so you always know exactly which tool to grab from the toolbox.
What is the List Interface?
In Java, a List is an ordered collection that allows duplicate elements. Think of it like a numbered shelf in a warehouse — every item has a position (index), and you can have two identical items sitting side by side.
List is just an interface — it defines the rules. The actual classes (ArrayList, LinkedList, Stack, Vector) are the ones that follow those rules, each in their own way.
// You cannot do this:
List<String> list = new List<>(); // ❌ Interface can't be instantiated
// You do this instead:
List<String> list = new ArrayList<>(); // ✅
1. ArrayList — Your Go-To List
Think of ArrayList like a resizable array — imagine a shelf that automatically expands when you add more items.
Key Characteristics:
Backed by a dynamic array internally
Fast random access —
get(index)is O(1)Slow insertion/deletion in the middle — O(n)
Not thread-safe
import java.util.ArrayList;
ArrayList<String> student = new ArrayList<>();
// Adding elements
student.add("Prity");
student.add("Palak");
student.add("Soni");
// Accessing by index
System.out.println(student.get(0)); // Prity
// Removing an element
student.remove("Palak");
// Iterating
for(String student : student) {
System.out.println(student);
}
When to use in DSA:
Storing results of a traversal
Dynamic arrays in sliding window problems
Anytime you need fast access by index
2. LinkedList — The Flexible Chain
Think of LinkedList like a chain of machine parts — each part holds its own data and a pointer to the next part. Unlike ArrayList, there's no fixed shelf — every element knows only its neighbour.
Key Characteristics:
Each element (node) stores data + pointer to next node
Fast insertion/deletion — O(1) at head/tail
Slow random access — O(n) to reach index
Can be used as both List and Deque
import java.util.LinkedList;
LinkedList<String> subjects = new LinkedList<>();
// Adding elements
subjects.add("Maths");
subjects.addFirst("Physics"); // adds at beginning
subjects.addLast("Chemistry"); // adds at end
// Accessing
System.out.println(subjects.getFirst()); // Physics
System.out.println(subjects.getLast()); // Chemistry
// Removing
subjects.removeFirst();
// Iterating
for(String subject : subjects) {
System.out.println(subject);
}
When to use in DSA:
Implementing Queue or Stack
Problems involving frequent insertions/deletions
LRU Cache implementation
Confused about which one to pick? This table will make it crystal clear:
| Operation | ArrayList | LinkedList |
|---|---|---|
| Access by index | ✅ Fast O(1) | ❌ Slow O(n) |
| Insert at middle | ❌ Slow O(n) | ✅ Fast O(1) |
| Memory | Less | More ( stores pointers ) |
| Use in DSA | Random access | Frequent add/remove |
3. Stack — Last In, First Out
Think of Stack like a stack of plates — you always add and remove from the top. The last plate you placed is the first one you pick up. This is called LIFO (Last In, First Out).
Key Characteristics:
Extends
VectorclassOnly top element is accessible
push(), pop(), peek() are main methods
Not recommended for new code — use
ArrayDequeinstead
import java.util.Stack;
Stack<Integer> stack = new Stack<>();
// Push elements
stack.push(10);
stack.push(20);
stack.push(30);
// Peek — see top without removing
System.out.println(stack.peek()); // 30
// Pop — remove from top
System.out.println(stack.pop()); // 30
System.out.println(stack.pop()); // 20
// Check if empty
System.out.println(stack.isEmpty()); // false
When to use in DSA:
Balanced parentheses problem
Undo/Redo operations
DFS (Depth First Search)
Next Greater Element problems
4. Vector — The Outdated Cousin
Vector is almost identical to ArrayList — but with one key difference: it is thread-safe. Every method in Vector is synchronized, which makes it slower.
Honest truth: In modern Java development and DSA, you will almost never use Vector. It exists for legacy reasons.
import java.util.Vector;
Vector<String> v = new Vector<>();
v.add("One");
v.add("Two");
System.out.println(v.get(0)); // One
Simple rule:
Need a list? → Use
ArrayListNeed thread safety? → Use
CopyOnWriteArrayListVector? → Basically never 😅
Which One Should You Actually Use?
Here's the quick decision guide — bookmark this!
| Situation | Use This |
|---|---|
| Default choice for most problems | ArrayList |
| Frequent insert/delete at ends | LinkedList |
| Need LIFO / undo functionality | Stack (or ArrayDeque) |
| Legacy code only | Vector |
| Implementing Queue in DSA | LinkedList or ArrayDeque |
Final Thoughts
Coming from Mechanical Engineering, I used to think more options = more confusion. But just like choosing between a bolt and a rivet, once you understand what each tool is built for, the choice becomes obvious.
Quick recap:
ArrayList— fast access, dynamic array, your defaultLinkedList— fast insert/delete, node-based chainStack— LIFO, great for DSA problemsVector— thread-safe but outdated, avoid in new code
This is Part 1 of my Java Collections Series. Next up — Queue Interface: ArrayDeque & PriorityQueue.
If this helped you, drop a reaction and follow for Part 2! 🚀