Skip to content
Java collections 6 min read

ArrayList

ArrayList is Java’s go-to resizable array. Unlike a plain array whose size is fixed at creation, an ArrayList grows (and shrinks) automatically as you add or remove elements — making it the workhorse of everyday Java programming.

What is ArrayList?

ArrayList<E> lives in the java.util package and implements the List interface. Under the hood it wraps a regular Object[] array, but you never have to manage its capacity yourself.

import java.util.ArrayList;

public class BasicList {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Cherry");
        System.out.println(fruits);
    }
}

Output:

[Apple, Banana, Cherry]

Creating an ArrayList

There are several ways to construct one:

import java.util.ArrayList;
import java.util.List;

public class CreatingArrayList {
    public static void main(String[] args) {
        // Default initial capacity (10)
        ArrayList<Integer> nums = new ArrayList<>();

        // With an initial capacity hint (avoids early resizing)
        ArrayList<Integer> sized = new ArrayList<>(50);

        // From an existing collection
        List<String> copy = new ArrayList<>(List.of("X", "Y", "Z"));

        System.out.println(copy);
    }
}

Output:

[X, Y, Z]

Tip: If you already know the approximate number of elements, pass that as the initial capacity. It avoids unnecessary array reallocations and improves performance.

Common Operations

Adding Elements

import java.util.ArrayList;

public class AddElements {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        list.add("One");           // append
        list.add("Three");
        list.add(1, "Two");        // insert at index 1

        System.out.println(list);  // [One, Two, Three]
    }
}

Output:

[One, Two, Three]

Accessing Elements

import java.util.ArrayList;

public class AccessElements {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("A", "B", "C"));

        String first = list.get(0);   // "A"
        int idx = list.indexOf("B");  // 1
        int size = list.size();       // 3

        System.out.println(first + " at index " + idx + ", size=" + size);
    }
}

Output:

A at index 1, size=3

Updating and Removing

import java.util.ArrayList;

public class ModifyList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("cat");
        list.add("dog");
        list.add("bird");

        list.set(1, "fish");      // replace "dog" → "fish"
        list.remove("cat");       // remove by value
        list.remove(0);           // remove by index (now removes "fish")

        System.out.println(list); // [bird]
    }
}

Output:

[bird]

Warning: remove(int index) and remove(Object o) are different overloads. With an ArrayList<Integer>, calling remove(1) removes the element at index 1. To remove the value 1, use remove(Integer.valueOf(1)). See Autoboxing & Unboxing for more context.

Iterating

You can loop over an ArrayList in multiple ways:

import java.util.ArrayList;
import java.util.Iterator;

public class IterateList {
    public static void main(String[] args) {
        ArrayList<String> colors = new ArrayList<>();
        colors.add("Red");
        colors.add("Green");
        colors.add("Blue");

        // 1. for-each (cleanest)
        for (String c : colors) {
            System.out.print(c + " ");
        }
        System.out.println();

        // 2. indexed for loop
        for (int i = 0; i < colors.size(); i++) {
            System.out.print(colors.get(i) + " ");
        }
        System.out.println();

        // 3. Iterator (safe removal during iteration)
        Iterator<String> it = colors.iterator();
        while (it.hasNext()) {
            String c = it.next();
            if (c.equals("Green")) it.remove();
        }
        System.out.println(colors);
    }
}

Output:

Red Green Blue 
Red Green Blue 
[Red, Blue]

Warning: Never call list.remove() inside a for-each loop directly — it throws ConcurrentModificationException. Use an Iterator or the removeIf() method instead.

Bulk Operations

import java.util.ArrayList;
import java.util.Collections;

public class BulkOps {
    public static void main(String[] args) {
        ArrayList<Integer> nums = new ArrayList<>();
        nums.add(3); nums.add(1); nums.add(4); nums.add(1); nums.add(5);

        Collections.sort(nums);               // sort ascending
        System.out.println("Sorted: " + nums);

        nums.removeIf(n -> n < 3);            // remove all < 3 (Java 8+)
        System.out.println("Filtered: " + nums);

        nums.replaceAll(n -> n * 2);          // double every element
        System.out.println("Doubled: " + nums);
    }
}

Output:

Sorted: [1, 1, 3, 4, 5]
Filtered: [3, 4, 5]
Doubled: [6, 8, 10]

Useful ArrayList Methods — Quick Reference

MethodWhat it does
add(E e)Appends element to the end
add(int i, E e)Inserts at index i
get(int i)Returns element at index i
set(int i, E e)Replaces element at index i
remove(int i)Removes element at index i
remove(Object o)Removes first occurrence of o
size()Number of elements
isEmpty()true if size is 0
contains(Object o)true if element exists
indexOf(Object o)First index of o, or -1
clear()Removes all elements
addAll(Collection c)Appends all elements from c
subList(from, to)View of a portion of the list
toArray()Returns an Object[] snapshot
trimToSize()Shrinks internal array to current size

Sorting an ArrayList

You can sort with Collections.sort() or list.sort() (Java 8+):

import java.util.ArrayList;
import java.util.Comparator;

public class SortList {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("Charlie"); names.add("Alice"); names.add("Bob");

        names.sort(Comparator.naturalOrder());        // alphabetical
        System.out.println("Asc: " + names);

        names.sort(Comparator.reverseOrder());        // reverse
        System.out.println("Desc: " + names);

        names.sort(Comparator.comparingInt(String::length)); // by length
        System.out.println("By length: " + names);
    }
}

Output:

Asc: [Alice, Bob, Charlie]
Desc: [Charlie, Bob, Alice]
By length: [Bob, Alice, Charlie]

For custom objects, see Comparable and Comparator.

Converting Between Array and ArrayList

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ConvertArrayList {
    public static void main(String[] args) {
        // Array → ArrayList
        String[] arr = {"x", "y", "z"};
        ArrayList<String> list = new ArrayList<>(Arrays.asList(arr));
        list.add("w");                       // mutable, unlike Arrays.asList alone
        System.out.println(list);

        // ArrayList → Array
        String[] back = list.toArray(new String[0]);
        System.out.println(Arrays.toString(back));
    }
}

Output:

[x, y, z, w]
[x, y, z, w]

Under the Hood

When you create new ArrayList<>(), Java allocates an internal Object[] with a default capacity of 10. Here is what happens as you add elements:

  1. Normal add — the element is stored at the next free slot. O(1) amortized.
  2. Capacity exceeded — Java allocates a new array of size oldCapacity * 1.5 (approximately), copies all existing elements into it, then adds the new element. This grow operation is O(n) but happens infrequently.
  3. trimToSize() — shrinks the backing array to exactly size(), saving memory if the list has stopped growing.

Because elements sit in a contiguous block of memory, get(i) is O(1) — just a direct array offset. In contrast, insertion or removal in the middle is O(n) because subsequent elements must shift. If you do a lot of middle-insertions, consider LinkedList instead.

Note: ArrayList is not thread-safe. For concurrent access, wrap it with Collections.synchronizedList() or use CopyOnWriteArrayList from the Concurrent Collections package.

The iterator returned by ArrayList is fail-fast: it tracks an internal modCount. If the list is structurally modified outside the iterator, the next next() or remove() call throws ConcurrentModificationException. This is a safety check, not a guarantee — see the Java Memory Model page for thread-safety nuances.

ArrayList vs Array — When to Use Which

Featureint[] / String[]ArrayList<Integer> / ArrayList<String>
SizeFixed at creationGrows/shrinks automatically
PerformanceSlightly faster (no boxing)Tiny overhead from autoboxing
PrimitivesYes (int, double, …)No — stores objects only
Utility methodsNone built-inRich API (sort, search, etc.)
GenericsNoYes

Use a plain array when size is known, performance is critical, or you need to store primitives without boxing overhead. Use ArrayList for everything else.

  • List Interface — the contract ArrayList implements, and why coding to an interface matters
  • LinkedList — the other popular List implementation; great for frequent insertions/deletions
  • ArrayList vs LinkedList — a side-by-side performance and use-case comparison
  • Comparable — implement natural ordering so your objects sort correctly in any List
  • Iterator — safely traverse and remove elements from any collection
  • Collections Utility Class — sort, shuffle, reverse, and more built-in helpers for ArrayList
Last updated June 13, 2026
Was this helpful?