Data Structures - ArrayList

The ArrayList class is an array-based implementation of the List interface. Specifically, all elements of an ArrayList are stored in a Java array.

For example, an ArrayList named words has its underlying array of the size n. At this time, words are capable of storing at most n elements. We say the capacity of words is n elements. What will happen if we try to add n+1 elements to words? We will answer it after talking about common operations using ArrayList.

CRUD operations on an ArrayList

Let us write some example code using the ArrayList class. To use ArrayList, the concept of generic programming is needed. Simply speaking, you can think of generic programming as working with a general type T, where T can be replaced by any Java types such as int, float, String or even Object.

Please note that ArrayList and ArrayList<T> are different. The former is equivalent to ArrayList<Object>*. In the context of this article, ArrayList always refers to the latter generic version. Later in this series, we will learn more about generic programming.

As ArrayList was designed to be generic, you must specify the type of the elements that will be stored. For example, the declaration of an ArrayList named words whose elements are of type String is:

ArrayList<String> words = new ArrayList<String>();

Since the words object is intended to be used as a List, it is advisable to declare words to be of type List <String>. Remember that although declared as List, the words object is still an ArrayList (to learn more, please read our tutorial on Polymorphism in Java).

List<String> words = new ArrayList<String>();

To append a String at the end of the words list

words.add("school"); // words is now ["school"]

Now, remember that the words can only hold elements of type String. If you try to add a double,

words.add(1.0);

The compiler should complain that:

The method add(String) in the type List<String> is not applicable for the arguments (double)

To insert a String at index 0

words.add(0, "at"); // words is now ["at", "school"]

To access an element via index

String w = words.get(0); // w is "at"

The available elements in words have their indexes in [0, 1, ..., words.size() - 1]. Accessing a non-existing element results in an java.lang.IndexOutOfBoundsException exception.

To update an element via index

words.set(1, "work"); // words is now ["at" , "work"]

To remove an element via index

words.remove(0); // words is now ["work"]

Here is a test class for the mentioned CRUD operations:

// File: ArrayListTest.java
import java.util.ArrayList;
import java.util.List;

public class ArrayListTest {
    public static void printList(List<String> words) {
        for (int i = 0; i < words.size(); i++) {
            System.out.println("Words[" + i + "]: " + words.get(i));
        }
    }

    public static void main(String []args) {
        List<String> words = new ArrayList<String>();
        // append
        words.add("school");
        printList(words);

        words.add(0, "at");
        System.out.println("> Insert via index");
        printList(words);

        words.set(1, "work");
        System.out.println("> Update via index");
        printList(words);

        words.remove(0);
        System.out.println("> Remove via index");
        printList(words);

    }
}

The above code produce:

Words[0]: school

> Insert via index

Words[0]: at

Words[1]: school

Update via index

Words[0]: at

Words[1]: work

Remove via index

Words[0]: work

Using List Iterator

Quite often, you care about iterating the elements of a List without bothering their indexes. In this usage scenario, it is recommended to use Iterator. As an implementation of the List interface, the ArrayList class provides a method to create an Iterator useful for iterating all elements of it.

Like the ArrayList class, the Iterator class uses generic programming. So, it is necessary to specify the type in the declaration. For example, the declaration for an Iterator over the words List of String: Iterator<String> iterator = words.iterator();

Let us write another version of the printList method using Iterator:

import java.util.Iterator;

public static void printList(List<String> words) {
   Iterator<String> iterator = words.iterator();

   while(iterator.hasNext()) {
     String word = iterator.next();
     System.out.print(word + " ");
   }

   System.out.println();
}

As you see, the Iterator class is simple, yet powerful. Since Java 1.5 (released in 2005), code using Iterator is occasionally shorten using the new for-loop. Here is how to rewrite the above method with Java's for:loop

public static void printList(List<String> words) {

   for(String word : words) {
      System.out.print(word + " ");
   }
   System.out.println();
}

Capacity of an ArrayList

In the beginning, we said that an ArrayList uses a fixed-size internal array to hold its elements. If all available space in the internal array has been used up and more space is needed, the ArrayList has no choice other than acquiring a bigger array, copy the old elements to the new array and use the new array in place of the old one.

How much space will be allocated for the new array?

Since Java 5.0, the size of the internal array doubles every time it needs more space. In short, trying to add just one element to an ArrayList which is full will result in costly operations:

(1) Acquiring a bigger array

(2) Copy all elements from the old array to the new array, If you know how much elements the ArrayList is intended to store, it is recommended to ensure the capacity - or the size of the internal array - before adding the elements.Grow this ArrayList instance, if necessary,to ensure that it can hold at least the number of elements specifiedby the minimum capacity argument.

void   ensureCapacity(int minCapacity);

Sometimes, the ArrayList no longer grows, and you want to save memory. The method trimToSize() can help you. Internally, a new array whose size is exactly the number of elements being stored will be allocated. Then, all elements are copied to this new array, freeing the space of the bigger old one.

// Shrink the capacity of this ArrayList instance to be the list's current size

void trimToSize();

Here is an example on how to store a really big number of elements without bearing the cost of allocating new internal array:

import java.util.ArrayList;

public class ArrayListCapacityTest {
   public static void main(String []args) {

       ArrayList<Integer> numbers = new ArrayList<Integer>();
       int SIZE = 1000000;
       numbers.ensureCapacity(SIZE);

       for (int i = 0; i < SIZE; i++) {
           numbers.add(i);
       }

      numbers.trimToSize();
      System.out.println("Number of elements is " + numbers.size());
   }
}

The above code produce:

Number of elements is 1000000

Summary

  • The ArrayList class is an array-based generic implementation of the List interface.
  • The class offers CRUD operations via index
  • We can use Iterator or a for:loop to traverse an ArrayList.
  • If we are going to store a big number of elements, use ensureCapacity to reserve spaces for them.
Data Structure
Data Structure
Previous Article
Dictionary Class
Dictionary Class
Next Article
Lakshay Sharma
I’M LAKSHAY SHARMA AND I’M A FULL-STACK TEST AUTOMATION ENGINEER. Have passed 16 years playing with automation in mammoth projects like O2 (UK), Sprint (US), TD Bank (CA), Canadian Tire (CA), NHS (UK) & ASOS(UK). Currently, I am working with RABO Bank as a Chapter Lead QA. I am passionate about designing Automation Frameworks that follow OOPS concepts and Design patterns.
Reviewers
Virender Singh's Photo
Virender Singh

Similar Articles

Feedback