What you'll learn
- Quick answer
- What is a Java ArrayList?
- Creating an ArrayList (and why generics matter)
- Adding elements with add()
- Reading and updating: get(), set(), size()
- Removing elements (and a classic gotcha)
- Searching with contains() and indexOf()
- Iterating: for-each, index loop, and Iterator
- ArrayList vs plain arrays: which to use?
- FAQ
Quick Answer
A Java ArrayList is a resizable, ordered list from the java.util package that grows and shrinks automatically as you add or remove items. You create one with generics (like new ArrayList<String>()), then use add() to insert, get() and set() to read and update, remove() to delete, and size() to count. Unlike a plain array, its length is not fixed, which makes it the go-to choice when you do not know in advance how many elements you will store.
What is a Java ArrayList?
A Java ArrayList is a resizable list of objects that lives in the java.util package. Think of it as an array that can grow and shrink on its own. With a plain array you must decide the length up front (new int[10]) and you are stuck with it. An ArrayList has no such limit — you just keep adding, and it makes room for you behind the scenes.
Under the hood, an ArrayList is backed by an ordinary array. When it fills up, Java quietly creates a bigger array and copies everything across. You never see this happen, but it explains the performance traits we will look at later.
A few things to know before we write code:
- It keeps elements in insertion order and allows duplicates.
- Each element has an index starting at
0, just like an array. - It stores objects, not primitives — so
intbecomesInteger,doublebecomesDouble, and so on (Java autoboxes these for you).
This is one of the most-used classes in everyday Java, so getting comfortable with it early pays off. If you want a structured path around these fundamentals, our free Java course covers collections step by step.
Creating an ArrayList (and why generics matter)
First, import it. Then create one, telling Java what type of items it will hold using generics — the type inside the angle brackets.
import java.util.ArrayList;
import java.util.List;
// A list that holds Strings
List<String> names = new ArrayList<>();
// A list that holds Integers
List<Integer> scores = new ArrayList<>();The empty <> on the right is the diamond operator. Java figures out the type from the left side, so you do not have to repeat <String> twice.
Why bother with generics? They tell the compiler exactly what type is inside. That means the compiler catches mistakes for you, and you never have to cast values when you read them back:
names.add("Priya"); // fine
// names.add(42); // compile error: 42 is not a String
String first = names.get(0); // no cast neededNotice we declared the variable as List<String>, not ArrayList<String>. Coding to the List interface is a good habit: your code depends on what a list does, not which list it is, so you can swap the implementation later without rewriting everything.
Gotcha: you cannot write ArrayList<int>. Generics only work with objects, so use the wrapper class ArrayList<Integer> instead.
Adding elements with add()
The add() method appends an item to the end of the list. There is also an overload that inserts at a specific index and shifts everything after it to the right.
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Mango"); // [Mango]
fruits.add("Apple"); // [Mango, Apple]
fruits.add("Guava"); // [Mango, Apple, Guava]
// Insert at index 1, pushing the rest along
fruits.add(1, "Banana"); // [Mango, Banana, Apple, Guava]Adding at the end is cheap. Inserting in the middle (or at index 0) is more work, because every element after that position has to shift over by one — keep that in mind for big lists.
You can also copy in a whole collection at once with addAll():
List<String> more = new ArrayList<>();
more.add("Papaya");
more.add("Litchi");
fruits.addAll(more); // appends both to fruits
Reading and updating: get(), set(), size()
Use get(index) to read an element and set(index, value) to replace one. Both use zero-based indexes, exactly like an array.
String first = fruits.get(0); // "Mango"
fruits.set(0, "Sweet Lime"); // replaces index 0
// fruits is now [Sweet Lime, Banana, Apple, Guava, Papaya, Litchi]
int count = fruits.size(); // number of elements
boolean empty = fruits.isEmpty(); // true only if size() == 0Two things beginners often mix up:
- It is
size(), notlength. Arrays use the fieldarray.length; ArrayList uses the methodlist.size(). - Indexes must be in range. Calling
get(5)on a list of 3 items throws anIndexOutOfBoundsException. Valid indexes run from0tosize() - 1.
Removing elements (and a classic gotcha)
The remove() method has two forms, and this is where many beginners trip up. You can remove by index (an int) or by value (an object).
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.remove(1); // removes INDEX 1 -> [a, c]
list.remove("a"); // removes the VALUE "a" -> [c]
list.clear(); // removes everything -> []With a List<String> there is no confusion, because an index is an int and a value is a String. But watch what happens with a List<Integer>:
List<Integer> nums = new ArrayList<>();
nums.add(10);
nums.add(20);
nums.add(30);
nums.remove(1); // int argument => removes INDEX 1 (the value 20)
// nums is now [10, 30]Here remove(1) deletes the element at index 1, not the number 1. To remove by value, wrap it so Java picks the object overload:
nums.remove(Integer.valueOf(30)); // removes the VALUE 30 -> [10]This is the single most common ArrayList bug. When your list holds numbers, be deliberate about whether you mean an index or a value.
Searching with contains() and indexOf()
To check whether an item exists, use contains(). To find where it is, use indexOf().
fruits.contains("Apple"); // true or false
fruits.indexOf("Apple"); // the index, or -1 if not found
fruits.lastIndexOf("Apple"); // index of the last match, or -1These methods compare items using equals(), not ==. For String and the wrapper types (Integer, Double, and so on) that just works. If you store your own class, make sure it overrides equals() — otherwise contains() only returns true for the exact same object reference, which is rarely what you want.
Both contains() and indexOf() scan the list from the start, so on a very large list they get slower the further in the match is. For occasional lookups that is fine; for constant membership checks, a HashSet is a better fit.
Iterating: for-each, index loop, and Iterator
There are three common ways to loop through an ArrayList. The enhanced for loop (for-each) is the cleanest when you just need to read each element:
for (String fruit : fruits) {
System.out.println(fruit);
}Use a plain index loop when you also need the position, or want to modify elements as you go:
for (int i = 0; i < fruits.size(); i++) {
System.out.println(i + ": " + fruits.get(i));
}Important gotcha: do not remove items from a list while looping over it with a for-each. Doing so throws a ConcurrentModificationException:
// DON'T do this
for (String fruit : fruits) {
if (fruit.startsWith("A")) {
fruits.remove(fruit); // throws ConcurrentModificationException
}
}When you need to remove during iteration, use an Iterator and call its own remove() method, which is safe:
import java.util.Iterator;
Iterator<String> it = fruits.iterator();
while (it.hasNext()) {
String fruit = it.next();
if (fruit.startsWith("A")) {
it.remove(); // safe removal
}
}On newer Java, fruits.removeIf(fruit -> fruit.startsWith("A")); does the same thing in one line.
ArrayList vs plain arrays: which to use?
Both store an ordered, indexed sequence, but they solve slightly different problems. Here is how they compare:
| Feature | Plain array | ArrayList |
| Resizes automatically | No | Yes |
| Fixed length | Yes | No |
| Stores primitives directly | Yes | No (uses wrappers) |
| Built-in add / remove / contains | No | Yes |
| Size member | length (field) | size() (method) |
| Fast index access | Yes | Yes |
Performance in short: get() and set() by index are instant — O(1). Adding to the end is O(1) on average (occasionally the backing array is resized and copied). But inserting or removing in the middle is O(n), because elements have to shift. Searching with contains() or indexOf() is also O(n).
Recommendation: reach for an ArrayList by default whenever the number of items can change or you do not know it up front — which is most of the time. Use a plain array only when the size is fixed and known, you are storing primitives and care about raw memory or speed, or an API hands you one. Once you are comfortable here, explore LinkedList, HashSet, and HashMap in our free Java course to pick the right collection for each job.
Frequently Asked Questions
How do I get the number of elements in an ArrayList?
Use the size() method, for example list.size(). This is different from arrays, which use the length field. To check if a list has no elements, prefer list.isEmpty() over list.size() == 0 — it reads more clearly and does the same thing.
Can an ArrayList store int values?
Not directly, because generics only work with objects. You use the wrapper class instead: ArrayList<Integer>. Java autoboxes automatically, so you can still write list.add(5) and it converts the int to an Integer for you. The same applies to double (use Double), char (Character), boolean (Boolean), and the rest.
What is the difference between remove(int) and remove(Object) on an ArrayList?
remove(int index) deletes the element at that position, while remove(Object o) deletes the first element equal to that value. This only causes confusion with a List<Integer>, where a number could be read as either. To force removal by value, wrap it: list.remove(Integer.valueOf(30)) removes the value 30, whereas list.remove(30) would try to remove index 30.
How do I remove items while looping through an ArrayList?
Do not remove inside a for-each loop — it throws a ConcurrentModificationException. Instead, use an Iterator and call it.remove(), which safely deletes the last element returned by next(). On modern Java, the cleanest option is list.removeIf(x -> condition), which handles the whole thing in one line.
Is ArrayList vs LinkedList a big deal for beginners?
For most everyday code, no — ArrayList is the sensible default. It gives fast index access (get/set) and fast appends. LinkedList only wins when you frequently add or remove items at the very front or middle of a large list. Start with ArrayList, and switch only if you have measured a real performance problem.
