Skip to content
Dev Dump

πŸ“‹ Java List Interface - Complete Guide

β€œThe List interface provides ordered collections with indexed access, making it perfect for scenarios where element position matters and you need to maintain insertion order.”

The List interface is a subinterface of Collection that represents an ordered collection (sequence) where:

  • Elements are stored in insertion order
  • Indexed access is supported (get/set by position)
  • Duplicate elements are allowed
  • Null values are permitted (implementation dependent)
FeatureDescriptionExample
OrderedMaintains insertion order[a, b, c] stays [a, b, c]
IndexedAccess by integer indexlist.get(0) returns first element
DuplicatesSame element can appear multiple times[a, b, a] is valid
Positional OperationsInsert/remove at specific positionsadd(index, element)
Collection<E>
└── List<E> (interface)
β”œβ”€β”€ ArrayList<E> - Dynamic array implementation
β”œβ”€β”€ LinkedList<E> - Doubly-linked list implementation
β”œβ”€β”€ Vector<E> - Synchronized dynamic array (legacy)
└── Stack<E> - LIFO stack extending Vector (legacy)
OperationArrayListLinkedListVectorBest Choice
Random AccessO(1)O(n)O(1)ArrayList
Sequential AccessO(1)O(1)O(1)All equal
Insert at BeginningO(n)O(1)O(n)LinkedList
Insert at EndO(1)*O(1)O(1)*All equal
Insert at IndexO(n)O(n)O(n)Context dependent
Delete at BeginningO(n)O(1)O(n)LinkedList
Delete at EndO(1)O(1)O(1)All equal
Delete at IndexO(n)O(n)O(n)Context dependent
SearchO(n)O(n)O(n)All equal
Memory OverheadLowHighLowArrayList
Thread SafetyβŒβŒβœ…Vector

* Amortized complexity - may be O(n) during resize

public interface List<E> extends Collection<E> {
// Positional access operations
E get(int index);
E set(int index, E element);
void add(int index, E element);
E remove(int index);
// Search operations
int indexOf(Object o);
int lastIndexOf(Object o);
// List iteration
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
// Range operations
List<E> subList(int fromIndex, int toIndex);
// Java 8+ additions
default void replaceAll(UnaryOperator<E> operator);
default void sort(Comparator<? super E> c);
// Inherited from Collection
boolean add(E e);
boolean remove(Object o);
boolean contains(Object o);
int size();
boolean isEmpty();
Iterator<E> iterator();
// ... more methods
}
public class ListMethodExamples {
public void demonstrateListMethods() {
List<String> fruits = new ArrayList<>();
// Adding elements
fruits.add("Apple");
fruits.add("Banana");
fruits.add(1, "Orange"); // Insert at specific index
// Accessing elements
String firstFruit = fruits.get(0);
fruits.set(1, "Mango"); // Replace element at index
// Searching
int appleIndex = fruits.indexOf("Apple");
int lastAppleIndex = fruits.lastIndexOf("Apple");
// Removing elements
fruits.remove(0); // Remove by index
fruits.remove("Banana"); // Remove by object
// Range operations
List<String> subList = fruits.subList(0, 2);
// Sorting
fruits.sort(Comparator.naturalOrder());
// Replacing all elements
fruits.replaceAll(String::toUpperCase);
}
}

ArrayList is a resizable array implementation of the List interface that provides:

  • Fast random access (O(1) for get/set)
  • Efficient end operations (O(1) amortized for add/remove)
  • Low memory overhead
  • Dynamic resizing as needed
public class ArrayListConstructionExamples {
public void demonstrateConstruction() {
// Default constructor (initial capacity 10)
ArrayList<String> list1 = new ArrayList<>();
// With initial capacity
ArrayList<String> list2 = new ArrayList<>(100);
// From existing collection
List<String> existing = Arrays.asList("a", "b", "c");
ArrayList<String> list3 = new ArrayList<>(existing);
// Using Arrays.asList (fixed-size list)
List<String> fixedList = Arrays.asList("x", "y", "z");
// Using List.of (immutable list)
List<String> immutableList = List.of("p", "q", "r");
}
}
public class ArrayListPerformanceExample {
public void demonstratePerformance() {
ArrayList<Integer> numbers = new ArrayList<>();
// Adding elements (O(1) amortized)
for (int i = 0; i < 1000000; i++) {
numbers.add(i);
}
// Random access (O(1))
int middleElement = numbers.get(500000);
// Sequential access (O(1) per element)
for (int number : numbers) {
// Process each number
}
// Insertion at beginning (O(n) - avoid for large lists)
numbers.add(0, -1);
// Insertion at end (O(1) amortized)
numbers.add(1000001);
}
}

LinkedList is a doubly-linked list implementation that provides:

  • Fast insertion/deletion at both ends (O(1))
  • Efficient sequential access
  • Flexible structure for frequent modifications
  • Higher memory overhead per element
public class LinkedListConstructionExamples {
public void demonstrateConstruction() {
// Default constructor
LinkedList<String> list1 = new LinkedList<>();
// From existing collection
List<String> existing = Arrays.asList("a", "b", "c");
LinkedList<String> list2 = new LinkedList<>(existing);
// LinkedList specific methods
LinkedList<String> list3 = new LinkedList<>();
list3.addFirst("First");
list3.addLast("Last");
list3.offer("Offer"); // Adds to end
list3.offerFirst("OfferFirst");
list3.offerLast("OfferLast");
}
}
public class LinkedListPerformanceExample {
public void demonstratePerformance() {
LinkedList<String> names = new LinkedList<>();
// Fast operations at both ends
names.addFirst("Alice"); // O(1)
names.addLast("Bob"); // O(1)
names.removeFirst(); // O(1)
names.removeLast(); // O(1)
// Queue operations
names.offer("Charlie"); // O(1) - adds to end
String first = names.peek(); // O(1) - views first element
String removed = names.poll(); // O(1) - removes and returns first
// Stack operations
names.push("David"); // O(1) - adds to beginning
String top = names.peek(); // O(1) - views first element
String popped = names.pop(); // O(1) - removes and returns first
}
}
public class LinkedListConsiderations {
public void demonstrateConsiderations() {
LinkedList<String> list = new LinkedList<>();
// 1. Random access is slow
for (int i = 0; i < 1000; i++) {
list.add("Item" + i);
}
// This is O(n) - very slow for LinkedList!
String item = list.get(500);
// 2. Better to use iterator or enhanced for-loop
for (String element : list) {
// O(1) per element - much faster
}
// 3. Use LinkedList-specific methods when possible
list.addFirst("NewFirst"); // Better than add(0, "NewFirst")
list.addLast("NewLast"); // Better than add("NewLast")
}
}
Use CaseArrayListLinkedListReasoning
Random Accessβœ… Best❌ PoorArrayList provides O(1) access
Sequential Accessβœ… Goodβœ… GoodBoth are efficient
Frequent Insertions❌ Poorβœ… BestLinkedList handles changes better
Memory Efficiencyβœ… Best❌ PoorArrayList has lower overhead
Queue Operations❌ Poorβœ… BestLinkedList has built-in queue methods
Stack Operations❌ Poorβœ… BestLinkedList has built-in stack methods