ArrayList
ArrayList internals, performance characteristics, and the patterns that make it the most-used collection in Java.
Last reviewed: January 2025
🔍 What Is It?
ArrayList is java.util.List backed by a dynamic array (Object[]).
Key Characteristics:
- →Random access: O(1) — direct array index
- →Add at end: O(1) amortized — occasionally O(n) for resize
- →Add/remove in middle: O(n) — must shift elements
- →Search (contains): O(n) — must scan entire array
- →Memory: contiguous memory — excellent CPU cache performance
Capacity vs Size:
- →size() — number of elements currently stored
- →capacity — size of the internal array (always >= size)
- →Initial capacity: 10 (or specified in constructor)
- →Growth factor: 1.5x (new capacity = old * 3/2 + 1)
Constructors:
- →
new ArrayList<>()— initial capacity 10 - →
new ArrayList<>(initialCapacity)— pre-allocate - →
new ArrayList<>(collection)— copy from collection
🎯 Why Do We Need It?
ArrayList is the workhorse of Java collections. It combines the simplicity of arrays (fast random access, contiguous memory) with the flexibility of dynamic sizing. In enterprise code, you use it to hold query results, build response objects, accumulate items, and pass data between layers.
🏗️ What Happens in Real Projects?
ArrayList is used in every Java project:
- →Query results:
List<Order> orders = new ArrayList<>(orderRepository.findAll()) - →Building responses: accumulate items then return
- →Batch processing: collect items then process in bulk
- →Sorting: ArrayList.sort() is highly optimized (TimSort)
⚙️ How It Works
How Resizing Works:
Initial: [_, _, _, _, _, _, _, _, _, _] // capacity 10, size 0
After 10 adds: [a, b, c, d, e, f, g, h, i, j] // capacity 10, size 10
11th add triggers resize:
1. Create new array of size 15 (10 * 3/2 + 1)
2. Copy all 10 elements to new array
3. Add 11th element
4. Old array becomes garbageWhy O(1) amortized for add:
Each element is copied at most once per resize. Total copies for n elements = n/2 + n/4 + ... = n. So average copies per element = 1. Hence O(1) amortized.
trimToSize():
Reduces internal array to exactly size(). Use after bulk loading to free unused capacity.
💻 Example
ArrayList Best Practices — How to use ArrayList efficiently in production code.
🤔 Common Confusions
❓ Why is ArrayList faster than LinkedList for most operations?
CPU cache locality. ArrayList stores elements in contiguous memory — when you access one element, nearby elements are loaded into CPU cache. Subsequent accesses are cache hits (very fast). LinkedList nodes are scattered across the heap — each access is likely a cache miss. This hardware effect makes ArrayList faster even for operations where LinkedList should theoretically be equal or better.
❓ What is the difference between ArrayList and Vector?
Vector is the legacy synchronized ArrayList from Java 1.0. Every method is synchronized, making it thread-safe but slow. ArrayList is not synchronized and faster for single-threaded use. For thread-safe lists, use CopyOnWriteArrayList or Collections.synchronizedList(). Never use Vector in new code.
🚨 Common Production Issues
Storing large objects in ArrayList — holding references prevents GC. If you load 100,000 JPA entities into a List, they all stay in memory until the list is cleared.
ArrayList.subList() is a view — modifying the parent list while holding a subList reference throws ConcurrentModificationException.
Autoboxing overhead — List<Integer> boxes every int. For large lists of primitives, use int[] or IntStream.
✅ Best Practices
Pre-size ArrayList when you know the approximate size: new ArrayList<>(expectedSize).
Use removeIf() for in-place filtering instead of iterating and removing.
Use replaceAll() for in-place transformation.
For frequent contains() checks on large lists, use a HashSet instead.
Return List<T> (interface), not ArrayList<T> (implementation).
🏛️ Architect's Note
For very large lists (millions of elements), consider alternatives: arrays (int[], Object[]) have less overhead; Stream<T> enables lazy processing without materializing the full list; database pagination avoids loading all records. The right tool depends on whether you need random access, streaming, or just iteration.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
List
The List interface — ordered, indexed, allows duplicates. When to use ArrayList vs LinkedList, and the patterns senior developers rely on.
LinkedList
LinkedList as both a List and a Deque — when it actually beats ArrayList and when to use ArrayDeque instead.