Mastering Collections in Java: Why and How to Use ArrayList

@Harsh
5 min read3 days ago

--

As I delve deeper into Java, I’ve discovered one of the most powerful features of the language: Collections. Collections provide a way to manage and manipulate groups of data in Java, solving many of the challenges posed by traditional arrays. In this blog, we’ll explore why collections are necessary, the limitations of arrays, and how ArrayList, one of the key implementations of the Java Collection Framework, overcomes these issues.

Why Do We Need Collections in Java?

Before diving into collections, let’s start by looking at how data was managed in Java using arrays.

Arrays in Java: A Limiting Approach

Arrays are one of the most basic data structures in Java, allowing us to store a fixed number of elements of the same type. While arrays are useful in certain cases, they come with significant limitations:

  1. Fixed Size: Once you declare an array, its size is fixed. You cannot modify the size of the array at runtime.
  2. Inflexibility: Arrays don’t provide built-in methods for adding, removing, or searching elements. This means that common operations like inserting or deleting elements require manual management.
  3. Inefficient Memory Usage: Arrays in Java are stored in stack memory, which can become inefficient for large amounts of dynamic data.
  4. No Built-in Methods: Arrays lack built-in functions for tasks like searching, sorting, or modifying elements, requiring developers to manually code these functionalities.

Let’s consider a simple example of an array:

int[] numbers = new int[5];  // Array of fixed size 5
numbers[0] = 10;
numbers[1] = 20;
// You cannot add more than 5 elements or remove any at runtime
numbers[5] = 60; // This will throw an "IndexOutOfBound" error

As shown above, if you declare an array of size 5, you can’t append or remove elements beyond its fixed size. This can lead to inefficient memory use if you don’t know the exact number of elements beforehand.

This is where collections come to the rescue!

The Power of Java Collections Framework

The Java Collections Framework (JCF) provides a set of data structures and algorithms for efficient data management. It includes interfaces like List, Set, Queue, and classes like ArrayList, LinkedList, HashSet, and TreeSet.

Two Ways to Create Data Structures in Java:

  1. Own Way: You could write your own data structure from scratch, but this is often complex and error-prone.
  2. Using Pre-Built Collections: Java provides pre-built collection classes and interfaces that can be used to manage data efficiently.

One of the most commonly used data structures in the Java Collection Framework is ArrayList, a dynamic array that overcomes the limitations of regular arrays.

Introducing ArrayList: A Dynamic, Flexible Solution

The ArrayList class in Java is a resizable array implementation of the List interface. Unlike arrays, an ArrayList can grow and shrink dynamically during runtime. This means you can add, remove, and modify elements as needed.

Here’s why ArrayList is a significant improvement over arrays:

  • Dynamic Size: You don’t need to specify the size upfront, as ArrayList grows automatically when elements are added.
  • Flexible Memory Allocation: Elements are stored in heap memory, which is more efficient for dynamic data.
  • Built-in Methods: ArrayList provides several methods for adding, removing, and accessing elements, simplifying common operations.

Let’s create an ArrayList and see how it works:

import java.util.ArrayList;

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

// Adding elements to the ArrayList
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Mango");

// Accessing an element in the ArrayList
System.out.println(fruits.get(1)); // Output: Banana
}
}

Methods of ArrayList Class

The ArrayList class provides several important methods for managing data. Let’s go through each method with examples.

1. add() Method

The add() method is used to add elements to the ArrayList. This method automatically increases the size of the ArrayList.

ArrayList<String> cars = new ArrayList<>();
cars.add("Tesla");
cars.add("BMW");
cars.add("Audi");
System.out.println(cars); // Output: [Tesla, BMW, Audi]

2. get() Method

The get() method retrieves an element from the ArrayList based on its index.

String car = cars.get(1);  // Get the second car (BMW)
System.out.println(car); // Output: BMW

3. set() Method

The set() method replaces an element at a specified index with a new value.

cars.set(1, "Mercedes");  // Replace BMW with Mercedes
System.out.println(cars); // Output: [Tesla, Mercedes, Audi]

4. remove() Method

The remove() method removes an element at the specified index or by value.

cars.remove(2);  // Remove the third element (Audi)
System.out.println(cars); // Output: [Tesla, Mercedes]

5. contains() Method

The contains() method checks if a specific element is present in the ArrayList.

boolean hasTesla = cars.contains("Tesla");
System.out.println(hasTesla); // Output: true

6. indexOf() Method

The indexOf() method returns the index of the first occurrence of the specified element. If the element is not found, it returns -1.

int index = cars.indexOf("Mercedes");
System.out.println(index); // Output: 1

7. addAll()

The addAll() method appends all elements of a specified collection to the end of an ArrayList.

ArrayList<String> newCars = new ArrayList<>();
newCars.add("Ford");
newCars.add("Toyota");

cars.addAll(newCars); // Append the new cars to the existing list
System.out.println(cars); // Output: [Tesla, Mercedes, Ford, Toyota]

8. containsAll()

The containsAll() method checks whether the ArrayList contains all the elements from a specified collection.

boolean hasAll = cars.containsAll(newCars);
System.out.println(hasAll); // Output: true

9. lastIndexOf()

The lastIndexOf() method returns the index of the last occurrence of the specified element in the ArrayList.

cars.add("Tesla");
int lastIndex = cars.lastIndexOf("Tesla");
System.out.println(lastIndex); // Output: 4

10. size()

The size() method returns the number of elements in the ArrayList.

int size = cars.size();
System.out.println(size); // Output: 5

If We Want to Add Elements at the Time of Creation: List.of()

If we want to add elements at the time of ArrayList creation, we can use List.of(), which creates an immutable list of specified elements:

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

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

This method is useful for creating an immutable list quickly with pre-defined values.

Traversing an ArrayList

Traversal is an essential part of working with collections. Let’s look at two ways to traverse an ArrayList:

1. Traditional for Loop

In a traditional for loop, we specify the starting point, condition, and increment step. This approach gives us the ability to access elements by their index.

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

2. Enhanced for Loop (For-Each Loop)

An enhanced for loop simplifies the traversal by iterating directly over the elements of the ArrayList.

for (String car : cars) {
System.out.println(car);
}

How ArrayList Solves Array’s Problems

Let’s revisit the issues with arrays and see how ArrayList addresses them:

  1. Fixed Size: Arrays have a fixed size, while ArrayList can dynamically resize itself. This is especially helpful when the size of the data set is unknown or changes frequently.
  2. Inflexibility: Arrays don’t have built-in methods for adding or removing elements. In contrast, ArrayList provides methods like add(), remove(), and contains(), simplifying these operations.
  3. Memory Usage: Arrays use stack memory, whereas ArrayList uses heap memory. Stack memory is limited and not ideal for dynamic data. The heap provides better management of memory for growing data structures.

Conclusion

The Java Collections Framework provides robust data structures to manage collections of objects. The ArrayList, a dynamic and flexible alternative to arrays, resolves the key limitations of arrays by offering dynamic resizing, efficient memory usage, and a set of built-in methods for data manipulation.

By mastering ArrayList methods like add(), remove(), get(), set(), and contains(), you can easily manage dynamic collections of data. Whether you’re building applications that require constant resizing of data or need efficient data traversal, the ArrayList provides a powerful solution.

Happy coding!

--

--