ArrayList in Java

Learn ArrayList in Java with practical examples, explanations, best practices, and real-world coding techniques.

ArrayList in Java is a resizable array implementation from the Java Collections Framework. Unlike a regular Java array, an ArrayList can automatically grow or shrink as elements are added and removed.

ArrayList is one of the most commonly used collection types in Java because it provides fast indexed access while allowing the collection size to change dynamically. It is useful for storing ordered collections such as users, products, tasks, messages, and other application data.

What Is ArrayList in Java?

ArrayList implements the List interface and internally uses a dynamically resized array to store its elements.

Because it is a List, ArrayList maintains insertion order, allows duplicate elements, and provides access to elements using indexes starting from 0.

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

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("C#");

System.out.println(languages);

Creating an ArrayList

An ArrayList can be declared using the List interface and initialized with the ArrayList implementation. This is generally preferred because the code depends on the interface rather than a specific implementation.

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

List<String> names = new ArrayList<>();

names.add("Alice");
names.add("Bob");
names.add("Charlie");

Java collections use generic types, so ArrayList<String> accepts strings, while ArrayList<Integer> accepts integer values. Collections work with objects, so primitive values such as int use wrapper types such as Integer.

Adding Elements to ArrayList

The add() method appends an element to the end of the list.

List<String> skills = new ArrayList<>();

skills.add("Java");
skills.add("Spring");
skills.add("SQL");

System.out.println(skills);

You can also insert an element at a specific index by using the overloaded add(index, element) method. Existing elements at that position and after it are shifted to the right.

List<String> skills = new ArrayList<>();

skills.add("Java");
skills.add("SQL");
skills.add("Spring");

skills.add(1, "C#");

System.out.println(skills);

Accessing ArrayList Elements

Use the get() method to retrieve an element at a particular index. ArrayList provides constant-time indexed access in typical usage.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("JavaScript");

String first = languages.get(0);
String second = languages.get(1);

System.out.println(first);
System.out.println(second);

Accessing an index outside the valid range throws an IndexOutOfBoundsException.

Updating an ArrayList Element

The set() method replaces the element at a specified index. It does not change the size of the list.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("C#");

languages.set(1, "TypeScript");

System.out.println(languages);

After calling set(1, "TypeScript"), the element at index 1 is replaced. No additional element is inserted.

Removing Elements from ArrayList

ArrayList provides several ways to remove elements. You can remove an element by index or remove a matching object.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("C#");

languages.remove(1);

System.out.println(languages);

To remove an object rather than an index, pass the object itself.

languages.remove("C#");

System.out.println(languages);

Removing Integer Values

A common source of confusion occurs with ArrayList<Integer> because remove(int) removes by index. To remove an Integer value, explicitly use Integer.valueOf().

List<Integer> numbers = new ArrayList<>();

numbers.add(10);
numbers.add(20);
numbers.add(30);

numbers.remove(Integer.valueOf(20));

System.out.println(numbers);

Finding Elements in ArrayList

ArrayList provides methods such as contains(), indexOf(), and lastIndexOf() for searching elements.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
languages.add("Java");

System.out.println(languages.contains("Python"));
System.out.println(languages.indexOf("Java"));
System.out.println(languages.lastIndexOf("Java"));

indexOf() returns the first matching index, while lastIndexOf() returns the last matching index. If no matching element exists, these methods return -1.

Checking the Size of an ArrayList

Use the size() method to determine how many elements are currently stored.

List<String> users = new ArrayList<>();

users.add("Alice");
users.add("Bob");
users.add("Charlie");

System.out.println(users.size());

The value returned by size() represents the number of elements, not the internal capacity of the ArrayList.

Iterating Through an ArrayList

ArrayList can be traversed using an enhanced for loop, a traditional indexed loop, or the forEach() method.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("C#");

for (String language : languages) {
    System.out.println(language);
}

When the index is required, an indexed loop can be used.

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

Sorting an ArrayList

The Collections.sort() method can sort elements in their natural order. For custom ordering, a comparator can be supplied.

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

List<Integer> numbers = new ArrayList<>();

numbers.add(40);
numbers.add(10);
numbers.add(30);
numbers.add(20);

Collections.sort(numbers);

System.out.println(numbers);

For descending order, use Collections.reverseOrder().

Collections.sort(numbers, Collections.reverseOrder());

System.out.println(numbers);

Adding Multiple Elements

The addAll() method adds all elements from another collection.

List<String> backend = new ArrayList<>();

backend.add("Java");
backend.add("C#");

List<String> additional = new ArrayList<>();

additional.add("Python");
additional.add("Go");

backend.addAll(additional);

System.out.println(backend);

Removing Multiple Elements

Java provides methods such as removeAll() and removeIf() for removing multiple elements based on a collection or condition.

List<Integer> numbers = new ArrayList<>();

numbers.add(10);
numbers.add(15);
numbers.add(20);
numbers.add(25);
numbers.add(30);

numbers.removeIf(number -> number > 20);

System.out.println(numbers);

The removeIf() method is especially useful when elements should be removed according to a condition.

Clearing an ArrayList

The clear() method removes all elements from the ArrayList.

List<String> users = new ArrayList<>();

users.add("Alice");
users.add("Bob");

users.clear();

System.out.println(users);
System.out.println(users.isEmpty());

ArrayList Capacity

An ArrayList has a current size representing the number of stored elements and an internal capacity representing the amount of storage available before the backing array needs to be resized.

The capacity is managed internally by Java. When additional space is required, the implementation can allocate a larger backing array and copy the existing elements into it. This resizing is why adding to the end of an ArrayList is considered O(1) amortized rather than O(1) for every individual insertion.

Initial Capacity

If the approximate number of elements is known in advance, an initial capacity can be supplied when creating an ArrayList. This can reduce the number of internal resizing operations as the collection grows.

import java.util.ArrayList;

ArrayList<String> users = new ArrayList<>(100);

users.add("Alice");
users.add("Bob");

Initial capacity affects internal storage allocation; it does not limit the maximum number of elements that the ArrayList can contain.

ArrayList Time Complexity

Understanding ArrayList complexity helps when choosing it for performance-sensitive code.

Operation Typical Complexity Reason
get(index) O(1) Direct indexed access
set(index, value) O(1) Direct replacement
add(value) O(1) amortized Append to the backing array
add(index, value) O(n) Elements may need to be shifted
get(index) search O(1) When the index is already known
contains(value) O(n) May scan the list
remove(index) O(n) Elements may need to be shifted
sort() O(n log n) Uses Java's list sorting implementation

ArrayList vs Array

Both arrays and ArrayList store ordered elements, but they are designed for different requirements.

Feature Array ArrayList
Size Fixed Dynamic
Indexed access O(1) O(1)
Primitive types Supported Use wrapper types
Built-in collection methods Limited Rich API

ArrayList vs LinkedList

Both implement the List interface, but they use different underlying structures and therefore have different performance characteristics.

Feature ArrayList LinkedList
Underlying structure Dynamic array Doubly linked list
get(index) O(1) O(n)
Append O(1) amortized O(1)
Memory layout Array-backed Separate linked nodes

For many general-purpose list workloads, ArrayList is a practical default because indexed access is fast and its array-backed storage has good locality. LinkedList is more specialized and should be selected when its particular list or deque behavior fits the workload.

Working with Custom Objects

ArrayList can store custom Java objects, making it useful for application-level data.

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

class User {
    String name;
    int age;

    User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

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

        users.add(new User("Alice", 25));
        users.add(new User("Bob", 30));

        for (User user : users) {
            System.out.println(user.name + " - " + user.age);
        }
    }
}

ArrayList with Streams

ArrayList works naturally with the Java Stream API, which can be useful for filtering, transforming, and processing collections.

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

List<Integer> numbers = new ArrayList<>();

numbers.add(10);
numbers.add(15);
numbers.add(20);
numbers.add(25);

List<Integer> evenNumbers = numbers.stream()
    .filter(number -> number % 2 == 0)
    .toList();

System.out.println(evenNumbers);

Converting ArrayList to an Array

The toArray() method can convert an ArrayList into an array.

List<String> languages = new ArrayList<>();

languages.add("Java");
languages.add("Python");
languages.add("C#");

String[] result = languages.toArray(new String[0]);

for (String language : result) {
    System.out.println(language);
}

Common ArrayList Mistakes

  • Trying to access an index that does not exist.
  • Using set() when a new element should actually be inserted.
  • Confusing remove(index) with remove(object).
  • Expecting contains() to provide constant-time lookup.
  • Using ArrayList when unique-value semantics are required instead of a Set.
  • Assuming ArrayList is thread-safe by default.
  • Using an excessively large initial capacity without a practical reason.
  • Choosing LinkedList solely because insertion is theoretically O(1), without considering the cost of locating the position.

When Should You Use ArrayList?

ArrayList is a strong choice when an application needs a dynamically sized, ordered collection with frequent indexed access.

  • You need a collection that grows dynamically.
  • You frequently access elements by index.
  • You need to preserve insertion order.
  • Duplicate values are allowed.
  • Most additions occur at the end of the collection.
  • You need Java Collection Framework methods such as filtering, sorting, searching, and bulk operations.

Practical Example: Managing Products

A simple application can use an ArrayList to maintain a collection of products. The list can grow as new products are added and can be searched or updated using standard methods.

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

class Product {
    String name;
    double price;

    Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
}

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

        products.add(new Product("Keyboard", 45.99));
        products.add(new Product("Mouse", 25.50));
        products.add(new Product("Monitor", 199.99));

        for (Product product : products) {
            System.out.println(
                product.name + " - $" + product.price
            );
        }
    }
}

Key Takeaways

  • ArrayList is a resizable array implementation of the Java List interface.
  • It maintains insertion order and allows duplicate elements.
  • Indexed access using get() is typically O(1).
  • Adding at the end is O(1) amortized, while inserting in the middle can require O(n) shifting.
  • Searching with methods such as contains() is O(n).
  • Use set() to replace an existing element and add() to insert a new one.
  • ArrayList is usually a practical choice for general-purpose indexed lists.

Code Examples

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

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

        languages.add("Java");
        languages.add("Python");
        languages.add("C#");

        System.out.println(languages);
    }
}
    
import java.util.ArrayList;
import java.util.List;

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

        skills.add("Java");
        skills.add("Python");
        skills.add("C#");

        skills.set(1, "TypeScript");
        skills.remove("C#");

        System.out.println(skills);
    }
}
    
import java.util.ArrayList;
import java.util.List;

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

        languages.add("Java");
        languages.add("Python");
        languages.add("JavaScript");

        System.out.println(languages.contains("Python"));
        System.out.println(languages.indexOf("Java"));
    }
}
    
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

        numbers.add(40);
        numbers.add(10);
        numbers.add(30);
        numbers.add(20);

        Collections.sort(numbers);

        System.out.println(numbers);
    }
}
    

Pro Tip

Use ArrayList when you need a dynamically sized ordered collection with frequent indexed access. For most general-purpose List usage, declaring the variable as List<T> keeps your code flexible while using ArrayList as the implementation.

🎨 IgKnight Docs

Master HTML, CSS, JS, Python, .NET and more with easy-to-follow lessons and practical code examples.

© 2025 IgKnight Learning Platform. All rights reserved.