I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this article, we’re going to take a look at ArrayList class from Java Collections Framework. We’ll discuss its properties, common use cases, as well as its advantages and disadvantages.

ArrayList resides within Java Core Libraries, so you don’t need any additional libraries. In order to use it just add the following import statement:

import java.util.ArrayList;

List represents an ordered sequence of values where some value may occur more than one time.

ArrayList is one of the List implementations built atop an array, which is able to dynamically grow and shrink as you add/remove elements. Elements could be easily accessed by their indexes starting from zero. This implementation has the following properties:

  • Random access takes O(1) time
  • Adding element takes amortized constant time O(1)
  • Inserting/Deleting takes O(n) time
  • Searching takes O(n) time for unsorted array and O(log n) for a sorted one

2. Creation

ArrayList has several constructors and we will present them all in this section.

First, notice that ArrayList is a generic class, so you can parameterize it with any type you want and the compiler will ensure that, for example, you will not be able to put Integer values inside a collection of Strings. Also, you don’t need to cast elements when retrieving them from a collection.

Secondly, it is good practice to use generic interface List as a variable type, because it decouples it from a particular implementation.

2.1. Default No-Arg Constructor

List<String> list = new ArrayList<>();
assertTrue(list.isEmpty());

We’re simply creating an empty ArrayList instance.

2.2. Constructor Accepting Initial Capacity

List<String> list = new ArrayList<>(20);

Here you specify the initial length of an underlying array. This may help you avoiding unnecessary resizing while adding new items.

2.3. Constructor Accepting Collection

Collection<Integer> number 
  = IntStream.range(0, 10).boxed().collect(toSet());

List<Integer> list = new ArrayList<>(numbers);
assertEquals(10, list.size());
assertTrue(numbers.containsAll(list));

Notice, that element of the Collection instance are used for populating underlying array.

3. Adding Elements

You may insert an element either at the end or at the specific position:

List<Long> list = new ArrayList<>();

list.add(1L);
list.add(2L);
list.add(1, 3L);

assertThat(Arrays.asList(1L, 3L, 2L), equalTo(list));

You may also insert a collection or several elements at once:

List<Long> list = new ArrayList<>(Arrays.asList(1L, 2L, 3L));
LongStream.range(4, 10).boxed()
  .collect(collectingAndThen(toCollection(ArrayList::new), ys -> list.addAll(0, ys)));
assertThat(Arrays.asList(4L, 5L, 6L, 7L, 8L, 9L, 1L, 2L, 3L), equalTo(list));

4. Iterating the List

There are two types of iterators available: Iterator and ListIterator. While the former gives you an opportunity to traverse the list in one direction, the latter allows you to traverse it in both directions.

Here we will show you only the ListIterator:

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
ListIterator<Integer> it = list.listIterator(list.size());
List<Integer> result = new ArrayList<>(list.size());
while (it.hasPrevious()) {
    result.add(it.previous());
}

Collections.reverse(list);
assertThat(result, equalTo(list));

You may also search, add or remove elements using iterators.

5. Searching in the List

We will demonstrate how searching works using a collection:

List<String> list = LongStream.range(0, 16)
  .boxed()
  .map(Long::toHexString)
  .collect(toCollection(ArrayList::new));
List<String> stringsToSearch = new ArrayList<>(list);
stringsToSearch.addAll(list);

5.1. Searching an Unsorted Array

In order to find an element you may use indexOf() or lastIndexOf() methods. They both accept an object and return int value:

assertEquals(10, stringsToSearch.indexOf("a"));
assertEquals(26, stringsToSearch.lastIndexOf("a"));

If you want to find all elements satisfying a predicate, you may filter collection using Java 8 Stream API (read more about it here) using Predicate like this:

Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = stringsToSearch
  .stream()
  .filter(matchingStrings::contains)
  .collect(toCollection(ArrayList::new));

assertEquals(6, result.size());

It is also possible to use a for loop or an iterator:

Iterator<String> it = stringsToSearch.iterator();
Set<String> matchingStrings = new HashSet<>(Arrays.asList("a", "c", "9"));

List<String> result = new ArrayList<>();
while (it.hasNext()) {
    String s = it.next();
    if (matchingStrings.contains(s)) {
        result.add(s);
    }
}

5.2. Searching a Sorted Array

If you have a sorted array, then you may use binary search algorithm which works faster than linear search:

List<String> copy = new ArrayList<>(stringsToSearch);
Collections.sort(copy);
int index = Collections.binarySearch(copy, "f");
assertThat(index, not(equalTo(-1)));

Notice that if an element is not found then -1 will be returned.

6. Removing Elements

In order to remove an element, you should find its index and only then perform the removal via remove() method. Overloaded version of this method, that accepts an object, searches for it and performs removal of the first occurrence of an equal element:

List<Integer> list = new ArrayList<>(
  IntStream.range(0, 10).boxed().collect(toCollection(ArrayList::new))
);
Collections.reverse(list);

list.remove(0);
assertThat(list.get(0), equalTo(8));

list.remove(Integer.valueOf(0));
assertFalse(list.contains(0));

But be careful when working with boxed types such as Integer. In order to remove a particular element, you should first box int value or otherwise, an element will be removed by its index.

You may as well use aforementioned Stream API for removing several items, but we won’t show it here. For this purpose we will use an iterator:

Set<String> matchingStrings
 = HashSet<>(Arrays.asList("a", "b", "c", "d", "e", "f"));

Iterator<String> it = stringsToSearch.iterator();
while (it.hasNext()) {
    if (matchingStrings.contains(it.next())) {
        it.remove();
    }
}

7. Summary

In this quick article, we had a look at the ArrayList in Java.

We showed how to create an ArrayList instance, how to add, find or remove elements using different approaches.

As usual, you can find all the code samples over on GitHub.

I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE LESSONS