# ArrayList

Course: [Java](https://www.devtutorials.ai/learn/java) · Section: Collections Framework
Source: https://www.devtutorials.ai/learn/java/collections-framework/arraylist

> Use ArrayList to add, remove, read, update, search, sort and loop through a resizable list, and understand capacity vs size.

Think about a train.

When more passengers turn up, the railway adds another coach. When fewer people travel, it removes one. The train is always the right length for the day. Each coach still has a number, so you can find your seat.

An `ArrayList` is like that train. It is a list that grows when you add items and shrinks when you remove them. Every item still has a position number, just like in an array.

In simple words: an `ArrayList` is an array that resizes itself.

## What You Will Learn

In this lesson, you will learn:

1. What an `ArrayList` is, and how it differs from an array.
2. How to create an `ArrayList`.
3. How to add, remove, read and update elements.
4. How to search for elements.
5. How to sort an `ArrayList`.
6. Several ways to loop through an `ArrayList`.
7. The most useful `ArrayList` methods.
8. The difference between capacity and size.

## Start With a Working Example

Press **Run**.

```java runnable title="A to-do list that grows, changes and shrinks"
import java.util.ArrayList;

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

        todo.add("Buy milk");
        todo.add("Pay bill");
        todo.add("Call Ravi");
        System.out.println("Start: " + todo);

        todo.set(1, "Pay electricity bill");
        todo.remove("Buy milk");
        todo.add("Book tickets");

        System.out.println("Now: " + todo);
        System.out.println("Tasks left: " + todo.size());
        System.out.println("First task: " + todo.get(0));
    }
}
```

Expected output:

```text
Start: [Buy milk, Pay bill, Call Ravi]
Now: [Pay electricity bill, Call Ravi, Book tickets]
Tasks left: 3
First task: Pay electricity bill
```

`add` puts items at the end. `set` changes one. `remove` takes one out, and the items after it move up to fill the gap. You never had to say how big the list was.

### Try This

Add `todo.add(0, "Wake up");` before the "Now" line. The new task goes to the front, and every other task moves back one place.

## Introduction to ArrayList

An **`ArrayList`** is a class in `java.util` that implements the `List` interface.

It stores its elements in an array inside it. When that inner array is full and you add one more item, `ArrayList` automatically:

1. creates a bigger array;
2. copies every element across;
3. adds the new item.

You never see this happen. You just keep calling `add`.

Key facts about an `ArrayList`:

- It keeps elements **in the order you add them**.
- It allows **duplicates**.
- It allows `null` elements.
- It holds **objects** only. For numbers, use wrapper types like `Integer`.
- Reading by index is **very fast**.

## ArrayList vs Array

| | Array | `ArrayList` |
|---|---|---|
| Size | Fixed when created | Grows and shrinks automatically |
| Created with | `new String[5]` or `{...}` | `new ArrayList<>()` |
| Holds primitives? | Yes, like `int[]` | No, use `Integer` |
| Number of elements | `array.length` | `list.size()` |
| Read an element | `array[i]` | `list.get(i)` |
| Change an element | `array[i] = x` | `list.set(i, x)` |
| Add or remove | Not possible without copying | `add` and `remove` |
| Printing | Needs `Arrays.toString` | Prints its contents directly |
| Speed | Slightly faster | Very slightly slower |

Use an **array** when the size never changes, or for large amounts of primitive data.

Use an **`ArrayList`** almost everywhere else.

## Creating ArrayLists

There are several ways to create one.

```text
ArrayList<String> a = new ArrayList<>();             // empty
List<String> b = new ArrayList<>();                  // empty, using the interface type
ArrayList<String> c = new ArrayList<>(50);           // empty, with room for 50 to start
ArrayList<String> d = new ArrayList<>(List.of("A", "B"));   // starts with values
```

Notes:

- The type in angle brackets, like `<String>`, says what the list can hold.
- `List<String> b = new ArrayList<>()` is the most common style. It uses the `List` interface for the variable.
- `List.of(...)` creates a fixed list that **cannot be changed**. Wrapping it in `new ArrayList<>(...)` gives you a changeable copy.

```java runnable title="Four ways to create an ArrayList"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> empty = new ArrayList<>();
        List<Integer> marks = new ArrayList<>();
        ArrayList<Double> prices = new ArrayList<>(100);
        List<String> cities = new ArrayList<>(List.of("Chennai", "Pune", "Delhi"));

        marks.add(85);
        prices.add(19.99);
        cities.add("Kochi");

        System.out.println("Empty: " + empty + ", size " + empty.size());
        System.out.println("Marks: " + marks);
        System.out.println("Prices: " + prices);
        System.out.println("Cities: " + cities);
    }
}
```

Expected output:

```text
Empty: [], size 0
Marks: [85]
Prices: [19.99]
Cities: [Chennai, Pune, Delhi, Kochi]
```

`new ArrayList<>(100)` still starts with **size 0**. The `100` only reserves room in advance. You will see why that matters under Capacity vs Size.

## Adding Elements

| Method | What it does |
|---|---|
| `add(value)` | Adds to the **end** |
| `add(index, value)` | Inserts at a position; later items move back one place |
| `addAll(otherList)` | Adds every item from another collection to the end |
| `addAll(index, otherList)` | Inserts every item from another collection at a position |

```java runnable title="Add to the end, at a position, or many at once"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> queue = new ArrayList<>();

        queue.add("Ravi");
        queue.add("Meena");
        System.out.println(queue);

        queue.add(0, "Asha");
        System.out.println(queue);

        queue.addAll(List.of("Arjun", "Divya"));
        System.out.println(queue);

        queue.add(2, "Kiran");
        System.out.println(queue);
    }
}
```

Expected output:

```text
[Ravi, Meena]
[Asha, Ravi, Meena]
[Asha, Ravi, Meena, Arjun, Divya]
[Asha, Ravi, Kiran, Meena, Arjun, Divya]
```

`add(0, "Asha")` put Asha at the front, and everyone else moved back.

The index for `add(index, value)` can be anything from `0` to `size()`. Using `size()` is the same as adding to the end.

## Removing Elements

| Method | What it does |
|---|---|
| `remove(index)` | Removes the element at that position, and returns it |
| `remove(value)` | Removes the **first** matching element; returns `true` if found |
| `removeAll(otherList)` | Removes every element that is also in the other list |
| `removeIf(condition)` | Removes every element that matches a condition |
| `clear()` | Removes everything |

When an element is removed, every element after it **moves forward one place**. The list never has gaps.

```java runnable title="Remove by position, by value, or by a rule"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>(List.of("Apple", "Mango", "Kiwi", "Mango", "Banana"));

        String removed = fruits.remove(0);
        System.out.println("Removed " + removed + ": " + fruits);

        fruits.remove("Mango");
        System.out.println("Removed first Mango: " + fruits);

        fruits.removeIf(f -> f.startsWith("B"));
        System.out.println("Removed names starting with B: " + fruits);

        fruits.clear();
        System.out.println("After clear: " + fruits + ", empty? " + fruits.isEmpty());
    }
}
```

Expected output:

```text
Removed Apple: [Mango, Kiwi, Mango, Banana]
Removed first Mango: [Kiwi, Mango, Banana]
Removed names starting with B: [Kiwi, Mango]
After clear: [], empty? true
```

`remove("Mango")` only removed the **first** Mango. The second one stayed.

`removeIf` takes a **lambda**, a short rule written as `f -> f.startsWith("B")`. It removes every element where the rule is true.

With a `List<Integer>`, `remove(2)` removes the element at **index 2**, not the value `2`. To remove the value, write `list.remove(Integer.valueOf(2))`. This catches out a lot of people.

`removeIf`, `forEach` and `sort` take a **lambda**, a short rule like `f -> f.startsWith("B")`. You met lambdas with functional interfaces. Read the arrow as "becomes": each element `f` becomes true or false.

## Accessing Elements

`get(index)` returns the element at a position. Indexes start at `0`, and the last index is `size() - 1`.

```text
list.get(0)                 // first element
list.get(list.size() - 1)   // last element
```

An index outside that range stops the program with an `IndexOutOfBoundsException`.

## Updating Elements

`set(index, value)` replaces the element at a position. It returns the **old** value.

`set` does not change the size. It can only replace an element that already exists.

```java runnable title="Read with get, replace with set"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> scores = new ArrayList<>(List.of(70, 85, 60, 92));

        System.out.println("First: " + scores.get(0));
        System.out.println("Last: " + scores.get(scores.size() - 1));

        int old = scores.set(2, 75);
        System.out.println("Changed " + old + " to " + scores.get(2));

        for (int i = 0; i < scores.size(); i++) {
            scores.set(i, scores.get(i) + 5);
        }
        System.out.println("After 5 bonus marks: " + scores);
    }
}
```

Expected output:

```text
First: 70
Last: 92
Changed 60 to 75
After 5 bonus marks: [75, 90, 80, 97]
```

The loop reads each mark with `get`, adds 5, and writes it back with `set`.

## Searching Elements

| Method | Returns |
|---|---|
| `contains(value)` | `true` if the value is in the list |
| `indexOf(value)` | The index of the first match, or `-1` |
| `lastIndexOf(value)` | The index of the last match, or `-1` |
| `isEmpty()` | `true` if the list has no elements |

These methods use `equals()` to compare, so they work correctly with strings.

```java runnable title="Find whether, and where, a value appears"
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> seats = new ArrayList<>(List.of("A1", "A2", "B4", "A2", "C1"));

        System.out.println("Has B4? " + seats.contains("B4"));
        System.out.println("Has D9? " + seats.contains("D9"));
        System.out.println("First A2 at: " + seats.indexOf("A2"));
        System.out.println("Last A2 at: " + seats.lastIndexOf("A2"));
        System.out.println("D9 at: " + seats.indexOf("D9"));
    }
}
```

Expected output:

```text
Has B4? true
Has D9? false
First A2 at: 1
Last A2 at: 3
D9 at: -1
```

`indexOf` returns `-1` for a value that is not there. Always check for `-1` before using the result as an index.

These searches check the elements one by one, from the start. For very large lists where you search often, a `HashSet` or `HashMap` is much faster.

## Sorting Elements

There are two common ways to sort an `ArrayList`:

- `Collections.sort(list)` sorts in natural order: numbers from small to large, text alphabetically.
- `list.sort(comparator)` sorts with your own rule.

A **comparator** is a rule that says how to compare two elements. Java has ready-made ones:

| Comparator | Sorts |
|---|---|
| `Comparator.naturalOrder()` | Small to large, A to Z |
| `Comparator.reverseOrder()` | Large to small, Z to A |
| `Comparator.comparing(String::length)` | By a value you choose, here the length |

Sorting changes the list itself.

```java runnable title="Natural order, reverse order and a custom rule"
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> marks = new ArrayList<>(List.of(72, 95, 58, 81));
        Collections.sort(marks);
        System.out.println("Low to high: " + marks);

        marks.sort(Comparator.reverseOrder());
        System.out.println("High to low: " + marks);

        List<String> names = new ArrayList<>(List.of("Meena", "Asha", "Ravi", "Arjun"));
        Collections.sort(names);
        System.out.println("A to Z: " + names);

        names.sort(Comparator.comparing(String::length));
        System.out.println("By length: " + names);
    }
}
```

Expected output:

```text
Low to high: [58, 72, 81, 95]
High to low: [95, 81, 72, 58]
A to Z: [Arjun, Asha, Meena, Ravi]
By length: [Asha, Ravi, Arjun, Meena]
```

`String::length` is a **method reference**. It is a short way to say "use each string's `length()`". Names with the same length keep their previous order.

## Iterating through ArrayList

There are four common ways to loop through an `ArrayList`.

### 1. Indexed for Loop

Use it when you need the position, or want to change elements with `set`.

### 2. for-each Loop

The simplest way to read every element.

### 3. Iterator

Use it when you need to remove elements while looping.

### 4. forEach Method

`list.forEach(...)` runs a lambda on every element. It is short and modern.

```java runnable title="Four ways to visit every element"
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> colours = new ArrayList<>(List.of("Red", "Green", "Blue"));

        System.out.println("1. Indexed for:");
        for (int i = 0; i < colours.size(); i++) {
            System.out.println("   " + i + ": " + colours.get(i));
        }

        System.out.println("2. for-each:");
        for (String c : colours) {
            System.out.println("   " + c);
        }

        System.out.println("3. Iterator:");
        Iterator<String> it = colours.iterator();
        while (it.hasNext()) {
            System.out.println("   " + it.next());
        }

        System.out.println("4. forEach:");
        colours.forEach(c -> System.out.println("   " + c.toUpperCase()));
    }
}
```

Expected output:

```text
1. Indexed for:
   0: Red
   1: Green
   2: Blue
2. for-each:
   Red
   Green
   Blue
3. Iterator:
   Red
   Green
   Blue
4. forEach:
   RED
   GREEN
   BLUE
```

| Loop | Gives the index? | Can remove safely? | Best for |
|---|---|---|---|
| Indexed `for` | Yes | Only with care | Positions, using `set` |
| for-each | No | No | Simple reading |
| `Iterator` | No | Yes | Removing while looping |
| `forEach` | No | No | Short one-line actions |

## ArrayList Methods

| Method | What it does | Example |
|---|---|---|
| `add(e)` | Adds to the end | `list.add("A")` |
| `add(i, e)` | Inserts at index `i` | `list.add(0, "A")` |
| `addAll(c)` | Adds every element of `c` | `list.addAll(other)` |
| `get(i)` | Returns the element at `i` | `list.get(2)` |
| `set(i, e)` | Replaces the element at `i` | `list.set(2, "B")` |
| `remove(i)` | Removes by index | `list.remove(0)` |
| `remove(o)` | Removes the first match | `list.remove("A")` |
| `removeIf(rule)` | Removes all that match | `list.removeIf(x -> x < 0)` |
| `size()` | Number of elements | `list.size()` |
| `isEmpty()` | `true` if empty | `list.isEmpty()` |
| `contains(o)` | `true` if present | `list.contains("A")` |
| `indexOf(o)` | First index, or `-1` | `list.indexOf("A")` |
| `clear()` | Removes everything | `list.clear()` |
| `sort(cmp)` | Sorts with a rule | `list.sort(Comparator.reverseOrder())` |
| `subList(a, b)` | A view of indexes `a` up to `b` | `list.subList(0, 3)` |
| `toArray(...)` | Copies into an array | `list.toArray(new String[0])` |

```java runnable title="subList, toArray and a few helpers"
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Integer> steps = new ArrayList<>(List.of(4200, 8100, 6500, 10200, 7300));

        System.out.println("First three days: " + steps.subList(0, 3));
        System.out.println("Best day: " + Collections.max(steps));
        System.out.println("Worst day: " + Collections.min(steps));

        Collections.reverse(steps);
        System.out.println("Reversed: " + steps);

        Integer[] asArray = steps.toArray(new Integer[0]);
        System.out.println("As an array: " + Arrays.toString(asArray));
    }
}
```

Expected output:

```text
First three days: [4200, 8100, 6500]
Best day: 10200
Worst day: 4200
Reversed: [7300, 10200, 6500, 8100, 4200]
As an array: [7300, 10200, 6500, 8100, 4200]
```

`Collections` (with an **s**) is a helper class full of static methods for collections, like `max`, `min`, `reverse` and `sort`.

`subList(0, 3)` returns indexes `0`, `1` and `2`. The end index is not included, just like `substring`.

## Capacity vs Size

These two words sound alike, but they mean different things.

- **Size** is how many elements the list **holds right now**. You read it with `size()`.
- **Capacity** is how many elements the **inner array has room for** before it must grow. You cannot read it directly.

Think of a bus with 40 seats and 12 passengers. The capacity is 40. The size is 12.

When the size reaches the capacity and you add one more element, `ArrayList` creates a bigger inner array, usually about one and a half times larger, and copies everything across. Then it adds the new element.

```text
add #1  → capacity 10, size 1
...
add #10 → capacity 10, size 10   (full)
add #11 → grows to capacity 15, copies 10 elements, size 11
```

That copying takes time. If you know you will add many elements, you can set the starting capacity yourself:

```text
List<Integer> big = new ArrayList<>(10000);
```

This avoids many grow-and-copy steps. The list still starts with **size 0**.

```java runnable title="Capacity is reserved room, size is real items"
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>(100);
        System.out.println("Size after new ArrayList<>(100): " + list.size());

        for (int i = 1; i <= 5; i++) {
            list.add(i * 10);
        }
        System.out.println("Size after 5 adds: " + list.size());

        list.ensureCapacity(500);
        list.trimToSize();
        System.out.println("Size is still: " + list.size());
        System.out.println("Contents: " + list);
    }
}
```

Expected output:

```text
Size after new ArrayList<>(100): 0
Size after 5 adds: 5
Size is still: 5
Contents: [10, 20, 30, 40, 50]
```

`ensureCapacity(500)` reserves room for 500 elements. `trimToSize()` shrinks the inner array down to exactly the current size, to save memory. Neither one changes the size.

| | Size | Capacity |
|---|---|---|
| Meaning | Elements actually stored | Room in the inner array |
| Read with | `size()` | Not directly readable |
| Changes when | You add or remove | The list grows, or you call `ensureCapacity` / `trimToSize` |
| Starts at | `0` | `10` by default, or the number you pass in |

**Easy Way to Remember:** **size** = passengers on the bus. **Capacity** = seats on the bus.

## Common mistakes

The following mistakes are common when using `ArrayList`. Each row shows what you see, why it happens and how to fix it.

| Symptom | Cause | Fix |
|---|---|---|
| `array required, but ArrayList found` | `[ ]` or `length` used on a list | Use `get(i)` and `size()` |
| `IndexOutOfBoundsException` | An index of `size()` or more | Use indexes `0` to `size() - 1` |
| The wrong number is removed | `remove(int)` removed by index | Use `remove(Integer.valueOf(x))` |
| `UnsupportedOperationException` | The list came from `List.of` | Copy it into `new ArrayList<>(...)` |
| `set` fails on a new list | `set` cannot add new elements | Use `add` |
| `ConcurrentModificationException` | The list changed during a for-each loop | Use `removeIf` or an `Iterator` |

## What to Remember

- An `ArrayList` is a resizable list. It keeps insertion order and allows duplicates.
- Create one with `List<String> list = new ArrayList<>();`. It holds objects, so use `Integer` for numbers.
- `add` to insert, `remove` to delete, `get` to read and `set` to replace. Later elements shift to fill gaps.
- `contains`, `indexOf` and `lastIndexOf` search the list. `indexOf` returns `-1` when nothing matches.
- Sort with `Collections.sort(list)` or `list.sort(comparator)`.
- Loop with an indexed `for`, a for-each, an `Iterator` or `forEach`. Remove while looping with an `Iterator` or `removeIf`.
- Size is how many elements it holds. Capacity is how much room its inner array has.

Next: Set and Map
