Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll look at the Java List interface. We’ll discuss the methods provided by List, its implementations, and usage scenarios.

2. Intro to Java Lists

Java is an object-oriented language, so most problems involve objects and behavior or actions associated with those objects.

Furthermore, we often need to manipulate more than one object of the same type at once and that’s where collections come into play. A Java List is an implementation of a collection that guarantees the order of elements and allows duplicates.

3. List Methods and Usage

Let’s have a look at the most important methods from the List interface and see how we can use them. For this example, we’ll use the ArrayList implementation.

3.1. Adding an Element

Let’s add new elements to a list using the method void add(E element):

@Test
public void givenAFruitList_whenAddNewFruit_thenFruitIsAdded(){
    List fruits = new ArrayList();
    assertEquals("Unexpected number of fruits in the list, should have been 0", 0, fruits.size());
        
    fruits.add("Apple");
    assertEquals("Unexpected number of fruits in the list, should have been 1", 1, fruits.size());
}

3.2. Checking if the List Contains an Element

We can check if the list contains an element using the method boolean contains(Object o):

@Test
public void givenAFruitList_whenContainsFruit_thenFruitIsInTheList(){
    List fruits = new ArrayList();
        
    fruits.add("Apple");
    assertTrue("Apple should be in the fruit list", fruits.contains("Apple"));
    assertFalse("Banana should not be in the fruit list", fruits.contains("Banana"));
}

3.3. Checking if the List Is Empty

Let’s check if a list is empty with the method boolean isEmpty():

@Test
public void givenAnEmptyFruitList_whenEmptyCheck_thenListIsEmpty(){
    List fruits = new ArrayList();
    assertTrue("Fruit list should be empty", fruits.isEmpty());
        
    fruits.add("Apple");
    assertFalse("Fruit list should not be empty", fruits.isEmpty());
}

3.4. Iterating the List

If we want to iterate over the list we can use the method ListIterator listIterator():

@Test
public void givenAFruitList_whenIterateOverIt_thenFruitsAreInOrder(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); // fruit at index 0
    fruits.add("Orange");// fruit at index 1
    fruits.add("Banana");// fruit at index 2
    int index = 0;
    for (Iterator it = fruits.listIterator(); it.hasNext(); ) {
        String fruit = it.next();
        assertEquals("Fruits should be in order", fruits.get(index++), fruit);
    }
}

3.5. Removing an Element

Let’s remove an element from the list using method boolean remove(Object o):

@Test
public void givenAFruitList_whenRemoveFruit_thenFruitIsRemoved(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); 
    fruits.add("Orange");
    assertEquals("Unexpected number of fruits in the list, should have been 2", 2, fruits.size());
        
    fruits.remove("Apple");
    assertEquals("Unexpected number of fruits in the list, should have been 1", 1, fruits.size());
}

3.6. Modifying an Element

Let’s modify an element of the list at a specified index using method E set(int index, E element):

@Test
public void givenAFruitList_whenSetFruit_thenFruitIsUpdated(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); 
    fruits.add("Orange");
        
    fruits.set(0, "Banana");
    assertEquals("Fruit at index 0 should be Banana", "Banana", fruits.get(0));
}

3.7. Getting the List Size

Let’s retrieve the size of the list using method int size():

List fruits = new ArrayList();
        
fruits.add("Apple"); 
fruits.add("Orange");
assertEquals("Unexpected number of fruits in the list, should have been 2", 2, fruits.size());

3.8. Sorting a List

We have many ways for sorting a list. Here let’s see how we can do it using the method default void sort(Comparator c) from the List interface.

This method needs a comparator as a parameter. Let’s provide it the natural order comparator:

@Test
public void givenAFruitList_whenSort_thenFruitsAreSorted(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); 
    fruits.add("Orange");
    fruits.add("Banana");
        
    fruits.sort(Comparator.naturalOrder());
        
    assertEquals("Fruit at index 0 should be Apple", "Apple", fruits.get(0));
    assertEquals("Fruit at index 1 should be Banana", "Banana", fruits.get(1));
    assertEquals("Fruit at index 2 should be Orange", "Orange", fruits.get(2));
}

3.9. Creating a Sublist

We can create a sublist from a list by providing the fromIndex and toIndex parameters to the method List subList(int fromIndex, int toIndex). We need to consider here that the toIndex is not inclusive:

@Test
public void givenAFruitList_whenSublist_thenWeGetASublist(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); 
    fruits.add("Orange");
    fruits.add("Banana");
        
    List fruitsSublist = fruits.subList(0, 2);
    assertEquals("Unexpected number of fruits in the sublist, should have been 2", 2, fruitsSublist.size());
        
    assertEquals("Fruit at index 0 should be Apple", "Apple", fruitsSublist.get(0));
    assertEquals("Fruit at index 1 should be Orange", "Orange", fruitsSublist.get(1));
}

3.10. Creating an Array With the List Elements

We can create an array that contains the list elements with method T[] toArray(T[] a):

@Test
public void givenAFruitList_whenToArray_thenWeGetAnArray(){
    List fruits = new ArrayList();
        
    fruits.add("Apple"); 
    fruits.add("Orange");
    fruits.add("Banana");
        
    String[] fruitsArray = fruits.toArray(new String[0]);
    assertEquals("Unexpected number of fruits in the array, should have been 3", 3, fruitsArray.length);
        
    assertEquals("Fruit at index 0 should be Apple", "Apple", fruitsArray[0]);
    assertEquals("Fruit at index 1 should be Orange", "Orange", fruitsArray[1]);
    assertEquals("Fruit at index 2 should be Banana", "Banana", fruitsArray[2]);
}

4. List Implementations

Let’s have a look at the most used implementations of the List interface in Java.

4.1. ArrayList

An ArrayList is a resizable-array implementation of the List interface. It implements all optional operations and permits all elements, including null. This class is roughly equivalent to Vector, except that it’s unsynchronized.

This is the most widely used implementation of the List interface.

4.2. CopyOnWriteArrayList

CopyOnWriteArrayList is a thread-safe variant of ArrayList. All mutative operations from this class (add, set, and so on) make a fresh copy of the underlying array.

This implementation is used for its intrinsic thread-safe capabilities.

4.3. LinkedList

LinkedList is a doubly-linked list implementation of the List and Deque interfaces. It implements all optional operations and permits all elements (including null).

4.4. Abstract List Implementations

We have two abstract implementations here that provide skeletal implementations of the List interface. These help minimize the effort required to extend and customize a List:

  • AbstractList – keeps a “random access” data store (such as an array) for its internal state
  • AbstractSequentialList – keeps a “sequential access” data store (such as a linked list) for its internal state

4.5. Other Concrete List Implementations

Here are two more concrete implementations worth discussing:

  • Vector – implements a growable array of objects. Also like an array, it contains components that can be accessed using an integer index. This class is synchronized. So if a thread-safe implementation isn’t needed, it’s recommended to use ArrayList in place of Vector.
  • Stack – represents a last-in-first-out (LIFO) stack of objects. It extends the class Vector and provides five additional operations that allow a vector to be treated as a stack.

Java also ships several specific List implementations that behave like one of the implementations discussed above.

5. Conclusion

In this article, we explored the Java List interface and its implementations. Lists are the go-to collection type when we only care about element order and allow duplicates. Since they handle growth internally, they are preferred to arrays.

As usual, the code snippets can be found over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.