Day 3 of DSA: ArrayList
Today I learned ArrayList in Java. It is similar to Python lists in that you do not predeclare the size, and you can expand it with add() just like append() in Python. ArrayList is a dynamic array implementation, so it resizes itself when capacity runs out.
ArrayList
An ArrayList in Java is a resizable array from java.util that grows automatically as elements are added or removed. Reads and writes by index are fast (O(1)), while occasional resizes make some add operations more expensive.
Syntax
ArrayList<Integer> list = new ArrayList<>();
Breakdown:
ArrayList: class name injava.util< >: generics angle bracketsInteger: wrapper class forintlist: reference variable namenew: allocates the object on the heapArrayList<>(): constructor invocation
What is Generics?
Generics let you write code that works with many data types safely. The actual type is supplied at use time, and the compiler enforces that type throughout the collection.
Example (type-safe for any element type T):
public static <T> void printArray(T[] elements) {
for (T element : elements) {
System.out.println(element);
}
}
What are Wrapper Classes?
Primitive types are not objects, so collections use wrapper classes: int -> Integer, char -> Character, double -> Double, and so on. Autoboxing/unboxing converts between primitives and wrappers automatically.
What is a Constructor?
A constructor initializes a new object instance. When you write new ArrayList<>(), Java runs the ArrayList constructor to set up its internal storage.
Minimal Example
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list); // prints [1, 2, 3]
}
}
How ArrayList is stored internally
- Backed by an
Object[]array calledelementData. - It tracks
size(number of elements) separately fromcapacity(length of the internal array). - When
size == capacityand you add more, it allocates a larger array (roughly 1.5x growth in modern JDKs), copies old elements, then continues. - Index lookups are O(1); appends are amortized O(1) but an occasional resize costs O(n).
Commonly used methods
add(E e)andadd(int index, E e)get(int index)andset(int index, E e)remove(int index)orremove(Object o)contains(Object o),indexOf(Object o)size(),isEmpty(),clear()ensureCapacity(int minCapacity)to reduce resize costs if you know the needed size up front.
Why use wrapper classes instead of primitives?
Collections store objects, not primitives. Wrappers make primitives usable in ArrayList, enabling features like null to indicate “no value.” The trade-off is extra memory and potential boxing/unboxing overhead.
Why and how size is not fixed
You never set a fixed length. The internal array is replaced with a larger one when needed, so size() changes as you add() or remove(). Capacity growth is automatic and hidden from your code.
Multidimensional ArrayList
You can build a list of lists for matrix-like data:
ArrayList<ArrayList<Integer>> matrix = new ArrayList<>();
for (int r = 0; r < 3; r++) {
ArrayList<Integer> row = new ArrayList<>();
for (int c = 0; c < 3; c++) {
row.add(r + c);
}
matrix.add(row);
}
System.out.println(matrix);
Difference between Array and ArrayList
- Size: arrays are fixed; ArrayLists resize automatically.
- Types: arrays can hold primitives; ArrayLists require wrapper objects.
- Performance: arrays avoid boxing and have no resize cost; ArrayLists offer convenience but add overhead.
- Syntax: arrays use
[ ]for access and initialization; ArrayLists use methods likeadd,get,set,remove.
Iteration options
- Index loop when you need positions:
for (int i = 0; i < list.size(); i++) { ... } - Enhanced for-loop when you just need values:
for (int value : list) { ... } forEachwith lambdas for concise actions:list.forEach(System.out::println);- Prefer iterators only when you need to remove while traversing.
Converting between arrays and ArrayList
- Array to list (mutable):
Integer[] arr = {1, 2, 3}; ArrayList<Integer> list = new ArrayList<>(Arrays.asList(arr)); - List to array:
Integer[] copy = list.toArray(new Integer[0]); - For primitives, use streams or loops because
Arrays.asListneeds wrappers.
Common pitfalls
- Modifying a list while looping with
for-eachthrowsConcurrentModificationException; use an iterator’sremoveinstead. ArrayListis not thread-safe; wrap withCollections.synchronizedListor useCopyOnWriteArrayListfor concurrent reads-heavy cases.ensureCapacitybefore bulkaddcalls to avoid repeated resizes.
When to pick ArrayList vs alternatives
- Use
ArrayListfor fast indexed access and mostly append operations. - Use
LinkedListwhen frequent inserts/removes occur in the middle (though cache effects often still favorArrayList). - Use
Stack/Dequeimplementations (likeArrayDeque) for queue/stack semantics instead ofArrayList.
Time complexity cheatsheet
get,set: O(1)addat end: amortized O(1); occasional resize O(n)add/removeat index: O(n) due to shiftingcontains,indexOf: O(n)
Comments