Choosing the right List
implementation is one of the most common decisions a Java developer makes. ArrayList
, LinkedList
, and Vector
are all part of the Java Collections Framework, but each has distinct performance, memory, and threading characteristics.
🔍 Overview of List Implementations
ArrayList
- Resizable array-backed implementation
- Fast access (O(1)), slow insert/remove in the middle (O(n))
- Not synchronized
LinkedList
- Doubly-linked list of nodes
- Fast insertion/removal (O(1)), slow access (O(n))
- Implements both
List
andDeque
Vector
- Synchronized version of ArrayList (legacy)
- Doubling capacity growth
- Rarely used in modern code
🧠 Internal Working and Memory Model
Feature | ArrayList | LinkedList | Vector |
---|---|---|---|
Backing | Array | Doubly linked nodes | Array |
Resizing | 1.5x | N/A | 2x |
Thread-safe | ❌ | ❌ | ✅ |
Memory Usage | Low | High (node overhead) | Medium |
List<String> list = new ArrayList<>();
list.add("A");
List<String> link = new LinkedList<>();
link.add("B");
Vector<String> vec = new Vector<>();
vec.add("C");
⏱️ Performance Comparison
Operation | ArrayList | LinkedList | Vector |
---|---|---|---|
get(index) |
O(1) | O(n) | O(1) |
add(element) |
O(1) amort. | O(1) | O(1) |
remove(index) |
O(n) | O(n) | O(n) |
Thread-safe | ❌ | ❌ | ✅ |
Memory Efficient | ✅ | ❌ | ⚠️ |
🎯 Real-World Use Cases
- ArrayList: Default choice when read-heavy and index access is frequent.
- LinkedList: Great for insert-heavy use like queues or undo history.
- Vector: Legacy codebases requiring synchronized access.
Deque<String> queue = new LinkedList<>();
queue.addLast("first");
queue.addLast("second");
queue.removeFirst(); // "first"
📌 What's New in Java Versions?
Java 8
- Stream and lambda support for all
List
types - Functional APIs:
removeIf
,replaceAll
,forEach
Java 9
- Immutable collections:
List.of(...)
,Set.of(...)
Java 10
var
keyword for type inference
Java 11
- Small performance enhancements
Java 17 & 21
- Collection improvements with compact memory and concurrency enhancements
✅ Functional Programming Support
List<String> names = Arrays.asList("Alice", "Bob", "Carol");
List<String> filtered = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
Works seamlessly across ArrayList
, LinkedList
, and Vector
.
❌ Common Pitfalls
- ❌ Using
LinkedList
for random access - ❌ Using
Vector
in modern code (synchronization overhead) - ❌ Forgetting
ArrayList
resizing cost for massive data
✅ Use ensureCapacity()
for large ArrayList
s
ArrayList<String> list = new ArrayList<>();
list.ensureCapacity(10000);
🔄 Refactoring Legacy Code
Before (Vector):
Vector<Integer> vector = new Vector<>();
vector.add(10);
After (Modern):
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
list.add(10);
🧠 Real-World Analogy
Think of ArrayList as a bookshelf with numbered slots, LinkedList as a treasure hunt (follow the map), and Vector as a locked safe — secure but slower to open.
❓ FAQ – Expert-Level Questions
-
Is ArrayList faster than LinkedList?
- For access-heavy tasks, yes.
-
Is LinkedList faster for deletion?
- Only if you're deleting at the ends or using iterator.
-
Why is Vector considered legacy?
- Because all its methods are synchronized, impacting performance.
-
Can I sort a LinkedList?
- Yes, using
Collections.sort(list)
.
- Yes, using
-
How to iterate efficiently?
- Use enhanced
for
loop or stream API.
- Use enhanced
-
Which list is best for queue operations?
LinkedList
orArrayDeque
.
-
Is ArrayList thread-safe?
- No. Wrap with
Collections.synchronizedList()
.
- No. Wrap with
-
When to use CopyOnWriteArrayList?
- For concurrent read-heavy scenarios.
-
Can I convert one list to another?
List<String> arrayList = new ArrayList<>(linkedList);
-
Which is best overall?
- Almost always:
ArrayList
.
- Almost always:
🏁 Conclusion and Key Takeaways
- Use
ArrayList
as the default choice unless you have specific reasons. - Choose
LinkedList
for insertion-heavy tasks, especially as a queue. - Avoid
Vector
unless you're maintaining legacy code.
🚀 Pro Tip: If you're unsure — benchmark your use case. Collections behave differently under scale.