Java tutorials > Core Java Fundamentals > Data Structures and Collections > When to use `ArrayList` vs `LinkedList`?

When to use `ArrayList` vs `LinkedList`?

Choosing between `ArrayList` and `LinkedList` in Java depends heavily on how you intend to use the list. Both implement the `List` interface, but their underlying implementations differ significantly, leading to different performance characteristics. This tutorial explores these differences to help you make informed decisions.

Underlying Data Structures

ArrayList: Based on a dynamically resizing array. Elements are stored in contiguous memory locations. This provides fast random access (getting an element by its index) but can be slow for insertions or deletions in the middle of the list because elements may need to be shifted.

LinkedList: Based on a doubly linked list. Each element (node) contains a value and pointers to the next and previous elements. This allows for fast insertions and deletions in the middle of the list but slower random access because you need to traverse the list to find a specific element.

Time Complexity Comparison

Understanding the time complexity of common operations is crucial for choosing the right data structure:

ArrayList:

  • get(index): O(1) - Constant time (very fast)
  • add(element): O(1) amortized (usually fast, but resizing the array takes O(n))
  • add(index, element): O(n) - Linear time (can be slow, especially near the beginning)
  • remove(index): O(n) - Linear time (can be slow, especially near the beginning)
  • remove(element): O(n) - Linear time. Requires searching for the element.

LinkedList:
  • get(index): O(n) - Linear time (can be slow)
  • add(element): O(1) - Constant time (very fast)
  • add(index, element): O(n) to find the index, O(1) to insert.
  • remove(index): O(n) to find the index, O(1) to remove.
  • remove(element): O(n) - Linear time. Requires searching for the element.

When to Use ArrayList

Choose `ArrayList` when:

  • You need frequent random access to elements (getting elements by index).
  • Insertions and deletions are primarily at the end of the list.
  • You don't need to frequently insert or delete elements in the middle of the list.
  • Memory usage is a concern (ArrayList generally has less overhead than LinkedList).

When to Use LinkedList

Choose `LinkedList` when:

  • You need frequent insertions and deletions in the middle of the list.
  • You don't need frequent random access to elements.
  • You are implementing a queue or deque (LinkedList implements the `Deque` interface efficiently).

Code Snippet: Adding Elements

This code demonstrates adding elements to both `ArrayList` and `LinkedList`. Notice the `add(index, element)` method, which inserts an element at a specific index. This is where `LinkedList` can potentially outperform `ArrayList` if insertions are frequent.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListComparison {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<>();
        List<String> linkedList = new LinkedList<>();

        // Adding elements
        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add(1, "Orange"); // Insert at index 1

        linkedList.add("Apple");
        linkedList.add("Banana");
        linkedList.add(1, "Orange"); // Insert at index 1

        System.out.println("ArrayList: " + arrayList);
        System.out.println("LinkedList: " + linkedList);
    }
}

Code Snippet: Retrieving Elements

This code demonstrates retrieving elements from both `ArrayList` and `LinkedList` using the `get(index)` method. `ArrayList` excels here due to its O(1) time complexity.

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListComparison {

    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<>();
        List<String> linkedList = new LinkedList<>();

        arrayList.add("Apple");
        arrayList.add("Banana");
        arrayList.add("Orange");

        linkedList.add("Apple");
        linkedList.add("Banana");
        linkedList.add("Orange");

        // Retrieving elements
        String arrayListElement = arrayList.get(1);
        String linkedListElement = linkedList.get(1);

        System.out.println("ArrayList element at index 1: " + arrayListElement);
        System.out.println("LinkedList element at index 1: " + linkedListElement);
    }
}

Real-Life Use Case Section

ArrayList: Imagine managing a list of products in an e-commerce application. You often need to access a product by its ID (index) quickly. `ArrayList` is suitable here because you frequently need random access and additions/removals are less frequent.

LinkedList: Consider implementing an undo/redo functionality in a text editor. Each action is a node in a linked list. When a user undoes, you remove the last node. When they redo, you add it back. `LinkedList` is a good choice for this scenario because you frequently insert and delete at the beginning or end of the list.

Best Practices

  • Profile your code: If performance is critical, profile your code with both `ArrayList` and `LinkedList` to see which performs better for your specific use case.
  • Consider the frequency of operations: Analyze the frequency of different operations (get, add, remove) to make an informed decision.
  • Use the appropriate data structure for the task: Don't just blindly use one or the other. Think about the requirements of your application.

Interview Tip

When asked about `ArrayList` vs `LinkedList` in an interview, focus on their underlying implementations, time complexities of common operations, and scenarios where each is more suitable. Emphasize that the choice depends on the specific use case and that profiling can be helpful for performance-critical applications.

Memory footprint

ArrayList: Generally more memory-efficient if you know the approximate size of the list beforehand because it stores elements contiguously. However, if the `ArrayList` needs to resize frequently, it can lead to memory overhead due to creating new, larger arrays and copying data.

LinkedList: Requires more memory per element because it stores pointers to the next and previous nodes. However, it doesn't need to resize, so it avoids the memory overhead associated with `ArrayList` resizing.

Alternatives

  • `ArrayDeque`: For queue and deque implementations, `ArrayDeque` (based on a resizable array) is often a better choice than `LinkedList` due to its better performance in many scenarios.
  • Custom data structures: For highly specialized use cases, consider implementing your own data structure tailored to your specific needs.
  • `CopyOnWriteArrayList`: Thread-safe variant of ArrayList optimized for read-heavy concurrent scenarios.

Pros of ArrayList

  • Fast random access (O(1)).
  • Memory-efficient (generally) if the size is known beforehand.

Cons of ArrayList

  • Slow insertions and deletions in the middle of the list (O(n)).
  • Resizing can be expensive (O(n)).

Pros of LinkedList

  • Fast insertions and deletions in the middle of the list (O(1) after finding the index).
  • Efficient for implementing queues and deques.

Cons of LinkedList

  • Slow random access (O(n)).
  • More memory overhead per element.

FAQ

  • Which is faster for adding elements to the end of the list?

    `ArrayList` is generally faster for adding elements to the end due to amortized O(1) time complexity. `LinkedList` also has O(1) complexity for adding to the end, but the overhead of creating a new node can sometimes make it slightly slower. However, the difference is usually negligible.
  • When should I use `LinkedList`?

    Use `LinkedList` when you need frequent insertions and deletions, especially in the middle of the list, and random access is not a primary requirement. Also, it's a good choice for implementing queues and deques.
  • When should I use `ArrayList`?

    Use `ArrayList` when you need frequent random access to elements by index, and insertions and deletions are less frequent or primarily at the end of the list.
  • Are `ArrayList` and `LinkedList` thread-safe?

    No, neither `ArrayList` nor `LinkedList` are inherently thread-safe. If you need thread-safe list operations, consider using `CopyOnWriteArrayList` (for read-heavy scenarios) or synchronizing access to the list using `Collections.synchronizedList()`.