ArrayList in Java is a dynamic array data structure implementation of the List interface, a part of the Java Collections Framework

ArrayList has the following features

  • Provides insertion-ordered iteration

  • Provides zero-based index operations (get, add, set, remove). Get, set operations run in constant-time performance. Add operation runs in amortized constant time. Other operations run in linear time

  • Permits null and duplicated elements

  • Elements are compared base on their equals method implementation

  • Unsynchronized implementation. In multi-threading environment with at least one thread modifies the list, it must be synchronized externally

Lets walk through this tutorial to explore them in more detail examples

The class hierarchy

ArrayList implements the List interface which extends from Collection and Iterable interfaces hierarchically

ArrayList vs Array and LinkedList

Array is a fixed size while ArrayList is a resizable array data structure implementation. Array provides run-time type safety while ArrayList provides compile time type safety. Learn more

LinkedList is a doubly linked list data structure implementation, more flexible than ArrayList as LinkedList can also work as a stack or queue

In term of efficiency, LinkedList consumes a bit more memory because it has to allocate a node object for each element in the list

Declare an ArrayList

As a result from the class hierarchy, you can declare and create an ArrayList with the following ways

@Test
public void declareAndCreate() {  
    List<Integer> lst1 = new ArrayList<>();
    assertThat(lst1).isInstanceOf(ArrayList.class);

    ArrayList<Integer> lst2 = new ArrayList<>();
}

Create and Initialize

  • Provide either Set.of or List.of factory method, since Java 9, or Arrays.asList factory method to the ArrayList(Collection) constructor to create and init an ArrayList in one line at the creation time
@Test
public void initWithListOfAndSetOf() {  
    List<Integer> arrayList1 = new ArrayList<>(List.of(3, 1, 2));
    assertThat(arrayList1).contains(3, 1, 2);

    List<Integer> arrayList2 = new ArrayList<>(Set.of(5, 4, 6));
    assertThat(arrayList2).contains(5, 4, 6);
}
  • You can also use add or addAll method to initialize an ArrayList after the creation time
@Test
public void initWithAdd() {  
    // Create a new ArrayList
    List<Integer> lst = new ArrayList<>();

    // Add elements to ArrayList
    lst.add(3);
    lst.add(1);
    lst.add(2);

    // Can add null element
    lst.add(null);

    // Can add duplicate element
    lst.add(2);
    assertThat(lst).hasSize(5);

    // The output ordering will be same as the insertion oder
    System.out.println(lst);
}

Learn more

Iterate over an ArrayList

  • You can iterate over an ArrayList by using either forEach(Consumer), since Java 8, or for-each and other index-loops (while, do-while, for-index)
@Test
public void forEachConsumer() {  
    List<Integer> lst = new ArrayList<>(List.of(1, 2, 3));

    lst.forEach(e -> System.out.printf("%d ", e));
}
  • Iterator and ListIterator can also be used to iterate
@Test
public void iterator() {  
    List<Integer> lst = new ArrayList<>(List.of(1, 2, 3));

    Iterator<Integer> iterator = lst.iterator();
    while (iterator.hasNext()){
        System.out.printf("%d ", iterator.next());
    }
}

Learn more

Retrieve and Filter

  • Retrieve an ArrayList element by using get(index)
@Test
public void get() {  
    List<Integer> lst = new ArrayList<>(List.of(1, 2, 3));

    int firstElement = lst.get(0);
    assertThat(firstElement).isEqualTo(1);
}
  • Since Java 8, you can use Stream API to filter and retrieve elements from an ArrayList

    The following example uses Stream API to get the first element with findFirst() and filter elements with filter(Predicate)

@Test
public void filterAndRetrieve() {  
    List<Integer> lst = new ArrayList<>(List.of(1, 2, 3));

    Integer firstElement = lst.stream().findFirst().orElse(null);
    assertThat(firstElement).isEqualTo(1);

    Integer[] arr = lst.stream().filter(e -> e >= 2).toArray(Integer[]::new);
    assertThat(arr).contains(2, 3);
}

Learn more

Examine, Add, Update and Remove

  • You can use contains method to examine if an element existing in an ArrayList, add methods to append and insert elements into the list, set method to update / replace element and remove methods to remove element from the list
@Test
public void containsAddUpdateRemoveSingleElement() {  
    List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3));
    Boolean contained = arrayList.contains(3);
    assertThat(contained).isTrue();

    arrayList.add(4); // appends an element
    arrayList.add(0, 10); // inserts at index 0
    arrayList.add(null);
    assertThat(arrayList).containsExactly(10, 1, 2, 3, 4, null);

    arrayList.set(0, 100); // update at index 0
    assertThat(arrayList).containsExactly(100, 1, 2, 3, 4, null);

    arrayList.remove(1); // removes at index 1
    assertThat(arrayList).containsExactly(100, 2, 3, 4, null);

    arrayList.remove(Integer.valueOf(2)); // removes an element
    assertThat(arrayList).containsExactly(100, 3, 4, null);
}
  • ArrayLists also support the above operations in bulk with containsAll, addAll, Java 8+ replaceAll, removeAll, Java 8+ removeIf
@Test
public void containsAddUpdateRemoveMultipleElements() {  
    List<Integer> arrayList = new ArrayList<>(List.of(1, 2, 3));
    Boolean contained = arrayList.containsAll(List.of(1, 2));
    assertThat(contained).isTrue();

    arrayList.addAll(List.of(4, 5));
    arrayList.addAll(0, List.of(10, 100));
    assertThat(arrayList).containsExactly(10, 100, 1, 2, 3, 4, 5);

    arrayList.replaceAll(e -> ++e);
    assertThat(arrayList).containsExactly(11, 101, 2, 3, 4, 5, 6);

    arrayList.removeAll(List.of(1, 11, 101));
    assertThat(arrayList).containsExactly(2, 3, 4, 5, 6);

    arrayList.removeIf(e -> e >= 3);
    assertThat(arrayList).contains(2);
}

Objects comparing in ArrayList

  • Internally, operations such as contains(Object) and remove(Object) compare objects based on their equals method implementation

    In the following example, list.contains(new Book(1, "a")) should return true but false, list.remove(new Book(1, "a")) should success but not due to lack of equals implementation on the user defined class

@Test
public void objectsComparingProblem(){  
    List<Book> list = new ArrayList<>();
    list.add(new Book(1, "a"));

    Boolean contained = list.contains(new Book(1, "a"));
    assertThat(contained).isFalse();

    list.remove(new Book(1, "a"));
    assertThat(list).hasSize(1);
}

static class Book {  
    int id;
    String title;

    Book(int id, String title) {
        this.id = id;
        this.title = title;
    }

    int getId() {
        return id;
    }

    String getTitle() {
        return title;
    }
}
  • You can fix the above problem by implement the equals method to the custom class as the below example
@Test
public void objectsComparingFixed(){  
    List<BookFixed> list = new ArrayList<>();
    list.add(new BookFixed(1, "a"));

    Boolean contained = list.contains(new BookFixed(1, "a"));
    assertThat(contained).isTrue();

    list.remove(new BookFixed(1, "a"));
    assertThat(list).hasSize(0);
}

static class BookFixed {  
    int id;
    String title;

    BookFixed(int id, String title) {
        this.id = id;
        this.title = title;
    }

    int getId() {
        return id;
    }

    String getTitle() {
        return title;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        BookFixed bookFixed = (BookFixed) o;
        return id == bookFixed.id &&
                Objects.equals(title, bookFixed.title);
    }
}

Sort an ArrayList

Sort an ArrayList of objects by using its instance's sort(Comparator) method in conjunction with Comparable and Comparator interfaces to control over the sort order

@Test
public void sortMultipleFields() {  
    Book book1 = new Book(1, "b");
    Book book2 = new Book(2, "c");
    Book book3 = new Book(3, "c");

    List<Book> list = Arrays.asList(book1, book2, book3);
    list.sort(Comparator
        .comparing(Book::getTitle, Comparator.reverseOrder())
        .thenComparing(Book::getId, Comparator.reverseOrder()));

    assertThat(list).containsExactly(book3, book2, book1);
}

Learn more

Conclusion

In this tutorial, we learned about ArrayList class hierarchy, features and operations. You can find below the full source code