All About ArrayList in Java: Important Insights

In this article, we will examine various aspects of ArrayList in Java. So, let’s get started.

All About ArrayList in Java

What is ArrayList in Java?

In a nutshell, ArrayList in Java is a resizable array. It internally stores the list of objects in an array.

Key Features of ArrayList in Java

Here are some key features of ArrayList in Java:

  1. Dynamic Sizing: ArrayList automatically handles resizing of the underlying array as elements are added or removed. This eliminates the need to manually manage memory allocation and resizing, making it convenient to work with collections of varying sizes.
  2. Indexed Access: Elements in an ArrayList are accessed using indexes, just like arrays. This provides efficient random access, allowing you to retrieve or modify elements at specific positions in constant time.
  3. Generics: ArrayList is a generic class, meaning it can hold elements of any data type. When you declare an ArrayList, you specify the type of elements it will hold. This ensures type safety and reduces the risk of runtime errors.
  4. Efficient Iteration: ArrayLists support efficient iteration using traditional for loops, enhanced for-each loops, or iterator objects. This makes it easy to traverse and process all elements in the list.
  5. Insertion and Deletion: ArrayList provides methods for adding and removing elements at specific indexes. While adding elements, you can insert them at a desired index, shifting existing elements to accommodate the new element. Similarly, you can remove elements by specifying their index, causing subsequent elements to shift.
  6. Null Elements: ArrayList allows the storage of null elements, making it suitable for scenarios where null values need to be part of the collection.
  7. Performance Considerations:
    • Random Access: ArrayList offers fast random access, allowing you to quickly retrieve elements using their indexes.
    • Insertion and Deletion: Adding or removing elements from the end of an ArrayList is efficient, but inserting or removing elements from the middle may involve shifting operations, resulting in performance overhead.
    • Searching: Searching for an element within an ArrayList requires linear search, which might be slower compared to using other data structures like HashSet or HashMap.
  8. Memory Overhead: ArrayLists have a slight memory overhead due to their dynamic resizing mechanism. This is because they allocate more memory than the current number of elements to accommodate potential future additions.
  9. Iterable Interface: ArrayList implements the Iterable interface, allowing you to use it in enhanced for-each loops and with iterator objects.
  10. Serialization: ArrayList is serializable, which means you can easily serialize an ArrayList and write it to an output stream or store it in files.
  11. Concurrency: ArrayList is not synchronized by default, meaning it is not thread-safe for concurrent access. If you need thread-safe operations, you should consider using Collections.synchronizedList() or other concurrent collections.

Java Code Example: ArrayList in Java

Here’s a Java code example that demonstrates some important methods of the ArrayList.

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

public class ArrayListExample {
    public static void main(String[] args) {
        // Create an ArrayList of strings
        ArrayList<String> fruits = new ArrayList<>();

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

        // Display the ArrayList
        System.out.println("Original ArrayList: " + fruits);

        // Accessing elements using indexes
        System.out.println("Element at index 2: " + fruits.get(2));

        // Check if an element exists
        boolean containsBanana = fruits.contains("Banana");
        System.out.println("Contains 'Banana': " + containsBanana);

        // Find the index of an element
        int indexOfOrange = fruits.indexOf("Orange");
        System.out.println("Index of 'Orange': " + indexOfOrange);

        // Size of the ArrayList
        int size = fruits.size();
        System.out.println("Size of ArrayList: " + size);

        // Remove an element
        fruits.remove("Grapes");

        // Display the modified ArrayList
        System.out.println("Modified ArrayList: " + fruits);

        // Sorting the ArrayList
        Collections.sort(fruits);

        // Display the sorted ArrayList
        System.out.println("Sorted ArrayList: " + fruits);
    }
}

Output:

Original ArrayList: [Apple, Banana, Orange, Grapes]
Element at index 2: Orange
Contains 'Banana': true
Index of 'Orange': 2
Size of ArrayList: 4
Modified ArrayList: [Apple, Banana, Orange]
Sorted ArrayList: [Apple, Banana, Orange]

In this example, we’ve covered several important methods of the ArrayList class:

  1. add(element): Adds elements to the ArrayList.
  2. get(index): Accesses an element using an index.
  3. contains(element): Checks if the ArrayList contains a specific element.
  4. indexOf(element): Finds the index of a specific element.
  5. size(): Returns the size of the ArrayList.
  6. remove(element): Removes an element from the ArrayList.
  7. Collections.sort(): Sorts the ArrayList in natural order.

Capacity of an ArrayList in Java

What is capacity? Well, it is nothing but the size of the internal array. The default capacity is 10.

Capacity is not the size of ArrayList, it is the size of the internal array, it means how many elements can be put to the ArrayList without growing it’s internal array.

When we write, List list = new ArrayList(); internally an array with size 10 is created to store the elements of the ArrayList.

We can always assign an initial capacity to an ArrayList by doing the below:

List list = new ArrayList(15); Here 15 is the initial capacity and so the size of the internal array.

How does an ArrayList grow dynamically?

As elements are added to an ArrayList,its capacity grows automatically. When the number of elements goes beyond the current capacity, then ArrayList increases it’s capacity by creating a new bigger-sized array and copies the elements from the old array to new array. and then adds the new element.

For example, List list = new ArrayList(); creates a ArrayList with capacity 10 , internally backed by an array with size 10.

The first 10 elements are added to the array. But when we add the 11th element, a new Array with bigger size(16) is created and the existing elements from the old array are copied to the new array using Arrays.copyOf and then the 11th element element is added to the new array. Now ArrayList discards the old array and uses the new array as it’s internal store for keeping the list of elements. The same process will repeat itself when we add 17th element to the ArrayList.

How the new size of the internal array is decided?

The growth policy is dependent upon the JDK version.
Till Java 6, int newCapacity = (oldCapacity * 3)/2 + 1;
From Java 7,int newCapacity = oldCapacity + (oldCapacity >> 1);

You can also explicitly increase the capacity of an already created ArrayList by calling ensureCapacity(int minCapacity).It increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.

Why it is better to give an initial capacity to an ArrayList in Java?

When one of these resizings operation occurs, the ArrayList copies the contents of the array into a new array that is around 1.5 times the capacity of the old one. This resize operation runs in O(n) time.

Let’s take an example of putting 1,00,000 elements in an ArrayList.

Then it will take hell lot of resizing of array and also a lot of time. The array will resize to 10, 16, 25, 38, 58,……,446803,670205,1005308.

The add method of ArrayList takes normally O(1) and on resize it takes an additional O(n).
So without initial capacity, adding 1,00,000 elements will take around :
1000000(for inserting 1,00,000 elements) + 16(for resize) + 25(for resize) + … + 670205(for resize) + 1005308(for resize)= 4015851 operations

But if we put the initial capacity as 1,00,000, then it will take :
1000000(for inserting 1,00,000 elements) + 1000000(for creating array with 1,00,000 size) = 2000000 operations

The advantages of providing initial capacity are:

  1. We can improve the memory usage
  2. We can improve the performance (i.e. additional time for creation of arrays can be saved)

Maximum allowed size of the internal Array

This is what is defined in the ArrayList class

/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE – 8;
The MAX_VALUE of Integer is  2^31-1 = 2147483647, therefor MAX_ARRAY_SIZE is 2147483639.

Conclusion: ArrayList in Java

ArrayList in Java is a dynamic array-like data structure that provides flexibility in managing and storing elements. It is part of the Java Collections Framework and is based on an array internally, but it automatically handles resizing as elements are added or removed.

Must Read: ArrayList Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *