Introduction
The ArrayList class in Java is a resizable array implementation of the List interface, offering dynamic storage for ordered collections of objects. Unlike fixed-size arrays, ArrayList automatically grows and shrinks as elements are added or removed. It provides fast random access (O(1)) and a rich set of methods for manipulating data. Mastering common ArrayList operations—such as adding, removing, searching, sorting, and iterating—is essential for effective data handling in Java applications, from simple data storage to complex algorithm implementations.
1. Core ArrayList Operations
A. Adding Elements
| Method | Description | Example |
|---|---|---|
add(E element) | Appends to the end | list.add("Apple"); |
add(int index, E element) | Inserts at specified index | list.add(0, "Banana"); |
Note: Adding at index
ishifts elements fromionward to the right.
B. Accessing Elements
| Method | Description | Example |
|---|---|---|
get(int index) | Returns element at index | String s = list.get(0); |
size() | Returns number of elements | int n = list.size(); |
Caution: Throws
IndexOutOfBoundsExceptionif index is invalid.
C. Modifying Elements
| Method | Description | Example |
|---|---|---|
set(int index, E element) | Replaces element at index | list.set(0, "Cherry"); |
D. Removing Elements
| Method | Description | Example |
|---|---|---|
remove(int index) | Removes by index | list.remove(0); |
remove(Object o) | Removes first occurrence of object | list.remove("Apple"); |
clear() | Removes all elements | list.clear(); |
Note:
remove(Object)uses.equals()for comparison.
E. Searching and Checking
| Method | Description | Example |
|---|---|---|
contains(Object o) | Checks if element exists | boolean has = list.contains("Apple"); |
indexOf(Object o) | Returns first index of element (-1 if not found) | int i = list.indexOf("Apple"); |
lastIndexOf(Object o) | Returns last index of element | int i = list.lastIndexOf("Apple"); |
isEmpty() | Checks if list has no elements | if (list.isEmpty()) { ... } |
2. Iteration Techniques
A. Enhanced For Loop (For-Each)
for (String fruit : list) {
System.out.println(fruit);
}
Best for: Simple read-only traversal.
B. Traditional For Loop (With Index)
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Best for: When index is needed.
C. Iterator (Safe for Removal)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
if (item.startsWith("X")) {
it.remove(); // Safe removal
}
}
Best for: Conditional removal during iteration.
D. forEach() (Java 8+)
list.forEach(System.out::println);
Best for: Functional-style processing.
3. Bulk Operations
A. Adding Collections
List<String> moreFruits = Arrays.asList("Mango", "Papaya");
list.addAll(moreFruits); // Appends all
list.addAll(1, moreFruits); // Inserts at index 1
B. Removing Collections
list.removeAll(moreFruits); // Removes all matching elements list.retainAll(moreFruits); // Keeps only elements in moreFruits
C. Checking Collections
boolean hasAll = list.containsAll(moreFruits); // True if all present
4. Sorting and Ordering
A. Natural Order (Java 8+)
Collections.sort(list); // For Comparable elements (e.g., String, Integer) list.sort(null); // Equivalent
B. Custom Comparator
// Sort by length list.sort(Comparator.comparing(String::length)); // Reverse order list.sort(Collections.reverseOrder());
C. Shuffling
Collections.shuffle(list); // Randomizes order
5. Converting to Other Types
A. To Array
String[] arr = list.toArray(new String[0]); // For primitives, use streams: int[] intArr = intList.stream().mapToInt(Integer::intValue).toArray();
B. To Other Collections
Set<String> set = new HashSet<>(list); // Remove duplicates LinkedList<String> linked = new LinkedList<>(list);
6. Performance Characteristics
| Operation | Time Complexity | Notes |
|---|---|---|
get(index) | O(1) | Fast random access |
add(element) | O(1) amortized | Occasional O(n) resize |
add(index, e) | O(n) | Shifts elements right |
remove(index) | O(n) | Shifts elements left |
contains(e) | O(n) | Linear search |
indexOf(e) | O(n) | Linear search |
Internal Structure: Backed by a dynamic array. Default initial capacity = 10. Grows by ~50% when full.
7. Common Use Cases
A. Dynamic List Building
List<Integer> numbers = new ArrayList<>();
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
numbers.add(sc.nextInt());
}
B. Filtering Elements
List<String> filtered = new ArrayList<>();
for (String s : list) {
if (s.length() > 3) {
filtered.add(s);
}
}
// Or with Java 8+ streams:
List<String> filtered = list.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
C. Removing Duplicates
List<String> unique = new ArrayList<>(new LinkedHashSet<>(list));
8. Best Practices
- Specify initial capacity if size is known:
List<String> list = new ArrayList<>(1000);
- Prefer
Listinterface for variable declaration:
List<String> names = new ArrayList<>(); // Good ArrayList<String> names = new ArrayList<>(); // Avoid
- Use
Iterator.remove()for safe in-loop removal. - Avoid
ArrayListfor frequent insertions/deletions in the middle—considerLinkedList. - Use
Collections.unmodifiableList()to protect against unintended modifications:
List<String> safeList = Collections.unmodifiableList(list);
9. Common Pitfalls
ConcurrentModificationException: Modifying list while iterating with for-each loop.
for (String s : list) {
list.remove(s); // ❌ Throws exception
}
- Autoboxing overhead: For primitive types, consider third-party libraries (e.g., Trove) or arrays.
- Memory overhead: Each
ArrayListhas object overhead; not ideal for huge datasets of primitives.
Conclusion
ArrayList is a versatile and efficient data structure for managing dynamic lists of objects in Java. Its combination of fast random access, automatic resizing, and rich API makes it the default choice for most list-based operations. By understanding its core methods, performance trade-offs, and best practices—such as proper initialization, safe iteration, and interface-based programming—developers can leverage ArrayList effectively in a wide range of applications. Whether building simple data processors or complex algorithms, mastering ArrayList operations is fundamental to proficient Java development. Always remember: choose the right tool for the job, and use ArrayList when you need fast access and dynamic sizing with infrequent middle insertions/deletions.