WalkthroughDifficulty: Intermediate1 min

What an ArrayList Does the Moment It Runs Out of Room

An array cannot grow, and an ArrayList is backed by an array and grows. Watching what happens at the boundary explains both its cost profile and a surprising number in its documentation.

From an empty list to one that has outgrown its array

Step 1 of 5

new ArrayList<>() allocates nothing

java
List<String> refs = new ArrayList<>();

The backing array is a shared, empty one. Capacity is zero, and a list nobody ever adds to costs almost nothing, which matters when a program holds thousands of them.

The first add allocates ten slots

java
refs.add("A");

Ten is the default initial capacity. Size is now one and capacity is ten, so the next nine adds cost nothing but a write.

The eleventh add finds the array full

There is no eleventh slot and no way to lengthen the array. The list allocates a new array about half as long again, which is fifteen slots.

Every element is copied across

Ten elements are copied from the old array into the new one, the list points at the new array, and the old one becomes garbage. Only then does the eleventh element go in.

Growth happens less and less often

Capacity after each growth, from the default start
GrowthCapacity
Initial10
First15
Second22
Third33

Because capacity grows by a proportion rather than by a fixed amount, the copies get further apart as the list gets longer. Averaged over many adds, appending is constant — which is why add is cheap despite occasionally copying everything.

The run to remember: growth is a copy, and its cost is spread thinly. When you know the final size, new ArrayList<>(50_000) skips every copy in the table above.