ArrayList in Java
ArrayList is one of the most widely used classes in Java, found in the java.util package.
It is a resizable (dynamic) array implementation of the List interface and stores elements in indexed, ordered, and growable form.
Where ArrayList Fits in the Collection Hierarchy
Iterable
│
Collection
│
List
│
ArrayList
This means ArrayList inherits methods from Iterable → Collection → List.
What is ArrayList?
An ArrayList is a dynamic array that:
- Grows automatically when more elements are added
- Stores elements in insertion order
- Provides index-based access like an array
- Allows duplicates
- Allows null values
- Belongs to Java Collections Framework
Unlike normal arrays, whose size is fixed, an ArrayList can expand or shrink at runtime.
Key Features of ArrayList
| Feature | Description |
|---|---|
| Dynamic Size | Automatically grows when elements are added. |
| Indexed Access | Get/set values using indexes like arrays. |
| Allows Duplicates | Same value may appear multiple times. |
| Ordered Collection | Maintains insertion order. |
| Fast Access (O(1)) | Very fast for reading (get/set). |
| Slower Insert/Delete | Slow when inserting/removing in the middle. |
| Not Synchronized | Not thread safe (use Vector instead if needed). |
Internal Working (How ArrayList Works)
Internal Structure:
ArrayList internally uses a dynamic array (Object[]) to store elements.
transient Object[] elementData;
How Resizing Works?
When ArrayList becomes full and you add a new element:
- It increases capacity by 50% of the previous size.
- New larger array is created.
- Old elements are copied to the new one.
Resize Formula (Java 8+):
newCapacity = oldCapacity + (oldCapacity / 2)
➡️ That's why append operations (add()) are amortized O(1).
Constructors of ArrayList
The ArrayList class provides three main constructors:

Default Constructor
The default constructor creates an empty ArrayList with no elements, but with an initial capacity that becomes 10 when the first element is added.
ArrayList<String> list = new ArrayList<>();
Internal Behavior
- Before first add → capacity = 0
- After first add → capacity = 10
Constructor with Initial Capacity
Creates an ArrayList with a given initial capacity, useful to avoid repeated resizing.
- When you know the number of elements in advance
- Better performance for large datasets
ArrayList<Integer> list = new ArrayList<>(50);
Create from Another Collection
Creates a new ArrayList and copies all elements from an existing collection.
ArrayList<String> list2 = new ArrayList<>(list1);
Internal Behavior
- Copies elements in the same order
- Capacity = size of the source collection
Example
List<String> list1 = List.of("A", "B", "C");
ArrayList<String> list2 = new ArrayList<>(list1);
Commonly Used ArrayList Methods
➤ Add Elements
Used to insert new elements into the list; when an index is given, the element is added at that specific position.
list.add("A");
list.add(1, "B"); // insert at index
➤ Access Elements
Retrieves the element stored at a specific index in the list.
list.get(0);
➤ Update Elements
Replaces an existing element at the given index with a new value.
list.set(1, "Updated");
➤ Remove Elements
Deletes elements from the list—either by index or by value.
list.remove(0); // by index
list.remove("A"); // by value
➤ Size
Returns the total number of elements currently stored in the list.
list.size();
➤ Search
Checks whether a given element exists in the list (returns true/false).
list.contains("A");
➤ Clear
Removes all elements from the list, making it completely empty.
list.clear();
➤ isEmpty
Checks whether the list contains no elements.
list.isEmpty();
➤ indexOf
Returns the index of the first occurrence of an element, or –1 if not found.
list.indexOf("A");
➤ lastIndexOf
Returns the index of the last occurrence of the specified element.
list.lastIndexOf("A");
➤ toArray
Converts the list elements into a normal array.
String[] arr = list.toArray(new String[0]);
Iterating Over an ArrayList
For-each Loop
A simple and clean way to iterate through all elements in sequential order.
for (String s : list) {
System.out.println(s);
}
Iterator
A safe way to traverse the list, which also allows element removal through the iterator.
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
Normal For Loop
Allows traversal using index values, useful when positions matter.
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
ListIterator (Advanced & Important)
Allows forward and backward traversal of the list.
ListIterator<String> litr = list.listIterator();
while (litr.hasNext()) {
System.out.println(litr.next());
}
Time Complexity
| Operation | Complexity | Notes / Definition |
|---|---|---|
| get() | O(1) | Accesses an element directly using its index, which requires no traversal. |
| set() | O(1) | Updates the value at a specific index instantly without shifting elements. |
| add(value) | O(1) amortized | Appends element at the end; occasionally resizing may happen, but average is constant-time. |
| add(index) | O(n) | Inserting at any position other than the end requires shifting elements to make space. |
| remove(index) | O(n) | Removing an element forces all elements after it to shift left. |
| contains() | O(n) | Searches element sequentially because ArrayList does not support binary search unless sorted. |
When to Use ArrayList
Use ArrayList when:
- Fast access required
- Order matters
- You want dynamic resizing
- Frequent additions at end, not middle
When NOT to Use ArrayList
Avoid ArrayList when:
- Frequent insert/delete in middle → use LinkedList
- Thread-safety required → use Vector or
Collections.synchronizedList(list)
- Unique elements required → use Set
ArrayList vs LinkedList
| Feature | ArrayList | LinkedList |
|---|---|---|
| Structure | Dynamic Array | Doubly Linked List |
| Access | Fast (O(1)) | Slow (O(n)) |
| Insert/Delete Middle | Slow | Fast (O(1)) if node known |
| Memory | Less | More (extra pointers) |
Complete Example
import java.util.ArrayList;
public class Example {
public static void main(String[] args) {
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");
System.out.println(fruits); // [Apple, Banana, Mango]
fruits.set(1, "Orange");
System.out.println(fruits.get(0)); // Apple
fruits.remove("Mango");
System.out.println(fruits); // [Apple, Orange]
}
}
Internal Structure Diagram
Before resizing (capacity 5)
Index: 0 1 2 3 4
-------------------------------------
Array: | A | B | C | null | null |
-------------------------------------
After resizing (capacity 7)
New Capacity = 5 + 2 = 7
Index: 0 1 2 3 4 5 6
-----------------------------------------------------
Array: | A | B | C | null | null | null | null |
-----------------------------------------------------
