6.3 Collections Framework: List, Set, Queue, and Deque APIs

Key Takeaways

  • The Collection interface forms the root of standard collection types, offering bulk operations, iterators, and predicate removals (removeIf); Map is an independent hierarchy.

  • List implementations maintain sequence and indexed access: ArrayList delivers O(1) random lookups backed by dynamic arrays, while LinkedList provides O(1) head/tail insertions via doubly-linked nodes.

  • Set implementations enforce uniqueness: HashSet provides O(1) hashing with one null allowed, LinkedHashSet preserves insertion order, and TreeSet enforces sorted ordering while strictly rejecting null elements.

  • Queue and Deque APIs distinguish exception-throwing methods (add, remove, element) from special-value methods (offer, poll, peek); ArrayDeque is the preferred null-rejecting implementation for both stacks and FIFO queues.

  • Immutable collection factories (List.of, Set.of) produce unmodifiable, null-hostile collections; in contrast, Arrays.asList creates a fixed-size, array-backed list that allows element replacements and permits null.

Last updated: October 2026

6.3 Collections Framework: List, Set, Queue, and Deque APIs

The Java Collections Framework (JCF) provides a unified architecture for managing groups of objects. Defined primarily in java.util, the framework separates abstract behavioral contracts (interfaces) from concrete data structure implementations. The 1Z0-829 examination tests deep familiarity with collection hierarchies, operation complexities, null handling nuances, queue/deque method dualities, and modern unmodifiable collection factories.


The Core Collection Hierarchy

The root interface for collections is java.lang.Iterable<T>, which enables the enhanced for loop. java.util.Collection<E> extends Iterable<E> and defines fundamental bulk and element operations inherited by List, Set, and Queue.

           Iterable<E>
               │
          Collection<E>
        ┌──────┼──────┐
        │      │      │
     List<E> Set<E> Queue<E>
        │      │      │
        │ NavigableSet Deque<E>

Note

Map<K, V> does not extend Collection. Maps represent key-value associations and define an independent hierarchy, although they expose collection views via keySet(), values(), and entrySet().

Core Collection methods include:

  • add(E e), addAll(Collection<? extends E> c): Inserts elements.
  • remove(Object o), removeAll(Collection<?> c): Removes matching elements.
  • removeIf(Predicate<? super E> filter): Removes all elements matching the given predicate in place (introduced in Java 8).
  • retainAll(Collection<?> c): Retains only elements contained in the specified collection (intersection).
  • contains(Object o), containsAll(Collection<?> c): Membership tests.
  • size(), isEmpty(), clear(), toArray(): Structural queries and conversions.

The List Interface and Implementations

A List<E> is an ordered collection (sequence) that allows duplicate elements and precise positional access via zero-based integer indices (get(int), set(int, E), add(int, E), remove(int)).

ArrayList vs. LinkedList

FeatureArrayList<E>LinkedList<E>
Underlying StructureResizable array (Object[])Doubly-linked nodes (Node<E>)
Positional Access (get/set)O(1)O(1) constant timeO(n)O(n) linear traversal
Append (add)Amortized O(1)O(1)O(1)O(1) constant time
Arbitrary Insert/DeleteO(n)O(n) due to System.arraycopy shiftO(1)O(1) once node is reached, but O(n)O(n) to locate index
Memory FootprintCompact contiguous memoryHigh per-element overhead (prev/next pointers)
Interface ContractsList, RandomAccess, CloneableList, Deque, Queue, Cloneable

The List<Integer>.remove() Overload Trap

A primary exam pitfall involves method overloading between remove(int index) and remove(Object o) on integer lists:

List<Integer> numbers = new ArrayList<>(List.of(10, 20, 30));

// Invokes remove(int index): removes element at index 1 (value 20)
numbers.remove(1); 
System.out.println(numbers); // Prints [10, 30]

// Invokes remove(Object o): removes the value 10
numbers.remove(Integer.valueOf(10));
System.out.println(numbers); // Prints [30]

// Attempting numbers.remove(30) treats 30 as an INDEX!
// numbers.remove(30); // Throws IndexOutOfBoundsException at runtime!

The Set Interface and Implementations

A Set<E> represents an unordered collection that prohibits duplicate elements. If an element e is already present (where existing.equals(e) is true), calling add(e) returns false and leaves the set unmodified.

Comparison of Core Set Implementations

ImplementationOrdering GuaranteeNull PolicyUnderlying Data StructureAccess Time
HashSetNo guaranteed order; can change on rehashAllows one nullHash table (HashMap)O(1)O(1) lookup/add
LinkedHashSetPreserves element insertion orderAllows one nullHash table + doubly-linked listO(1)O(1) lookup/add
TreeSetSorted order (natural Comparable or Comparator)Strictly rejects nullRed-Black tree (TreeMap)O(log⁡n)O(\log n) lookup/add

Warning

The TreeSet NullPointerException Trap Attempting to insert null into a TreeSet using natural ordering throws a NullPointerException immediately—even if the TreeSet is completely empty! Because TreeSet must compare elements via compareTo(), attempting to invoke a comparison on null triggers an exception.

NavigableSet Navigation Methods

TreeSet implements NavigableSet<E> (which extends SortedSet<E>), offering rich directional search methods:

  • lower(e): Greatest element strictly less than e (< e), or null.
  • floor(e): Greatest element less than or equal to e (<= e), or null.
  • ceiling(e): Least element greater than or equal to e (>= e), or null.
  • higher(e): Least element strictly greater than e (> e), or null.
  • pollFirst(), pollLast(): Retrieves and removes the lowest or highest element, or returns null if empty.
  • descendingSet(): Returns a reverse-order view of the set.
NavigableSet<Integer> set = new TreeSet<>(List.of(10, 20, 30, 40));
System.out.println(set.lower(20));   // 10 (strictly < 20)
System.out.println(set.floor(20));   // 20 (<= 20)
System.out.println(set.ceiling(25)); // 30 (>= 25)
System.out.println(set.higher(30));  // 40 (strictly > 30)

The Queue and Deque Interfaces

Queues model collections designed for holding elements prior to processing. Queue<E> handles First-In, First-Out (FIFO) ordering, while Deque<E> (Double-Ended Queue) supports insertion and removal at both ends, serving as both a FIFO queue and a Last-In, First-Out (LIFO) stack.

Method Dualities: Exception vs. Special Value

Queue operations are structured into two distinct sets of methods based on failure handling:

Operation TypeThrows Exception on FailureReturns Special Value (false or null)
Insertadd(e) (throws IllegalStateException if full)offer(e) (returns false if full)
Removeremove() (throws NoSuchElementException if empty)poll() (returns null if empty)
Examineelement() (throws NoSuchElementException if empty)peek() (returns null if empty)

Deque Operations and Stack Methods

Deque expands these dualities to both the head and tail:

  • Head Operations: addFirst, offerFirst, removeFirst, pollFirst, getFirst, peekFirst.
  • Tail Operations: addLast, offerLast, removeLast, pollLast, getLast, peekLast.
  • Stack Methods (LIFO):
    • push(e): Equivalent to addFirst(e) (inserts at head; throws exception if capacity reached).
    • pop(): Equivalent to removeFirst() (removes from head; throws NoSuchElementException if empty).
    • peek(): Equivalent to peekFirst() (inspects head; returns null if empty).

ArrayDeque as Preferred Stack and Queue

ArrayDeque is the industry-standard implementation of Deque backed by a circular array. It is significantly faster and more cache-efficient than LinkedList or legacy java.util.Stack (which is synchronized and extends Vector).

Warning

ArrayDeque Strictly Rejects null Unlike LinkedList, ArrayDeque does not permit null elements. Invoking deque.add(null), deque.push(null), or deque.offer(null) immediately throws a NullPointerException. This constraint exists because methods like poll() and peek() rely on null as a sentinel value indicating that the deque is empty.


Unmodifiable Collection Factories vs. Arrays.asList

Java 9 introduced static factory methods (List.of(), Set.of()) that produce unmodifiable collection instances. Understanding the operational differences between these factories, List.copyOf(), and Arrays.asList() is vital for the exam.

// 1. Arrays.asList: Fixed-size, backed by underlying array
String[] arr = { "A", "B" };
List<String> backedList = Arrays.asList(arr);
backedList.set(0, "Z"); // Allowed! Updates array: arr[0] becomes "Z"
// backedList.add("C"); // Throws UnsupportedOperationException (cannot change size)

// 2. List.of: Truly immutable instance
List<String> immutableList = List.of("A", "B");
// immutableList.set(0, "Z"); // Throws UnsupportedOperationException
// List.of("A", null);        // Throws NullPointerException (nulls forbidden!)

// 3. Set.of: Truly immutable set (rejects duplicates and nulls)
// Set.of("A", "A");          // Throws IllegalArgumentException (duplicate elements!)
// Set.of("A", null);         // Throws NullPointerException

// 4. List.copyOf: Unmodifiable defensive copy
List<String> copy = List.copyOf(backedList);
// If source contains null, List.copyOf throws NullPointerException!

Summary Comparison of Collection Creation Methods

CharacteristicList.of(...)Arrays.asList(...)new ArrayList<>(...)
MutabilityCompletely immutableFixed-size (in-place replacement allowed)Fully mutable (resizeable)
Null SupportRejects null (NullPointerException)Allows nullAllows null
Backing StoreInternal optimized classDirectly backed by source arrayIndependent heap array
Structural ModificationsThrows UnsupportedOperationExceptionThrows UnsupportedOperationExceptionPermitted (add, remove)
Test Your Knowledge

Consider the following code snippet:

List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.remove(1);
numbers.remove(Integer.valueOf(1));
System.out.println(numbers);

What is the output of this program?

A

[2]

B

An IndexOutOfBoundsException is thrown at runtime

C

[3]

D

[1]

Test Your Knowledge

Consider the following code snippet using ArrayDeque:

Deque<String> stack = new ArrayDeque<>();
stack.push("Alpha");
stack.push("Beta");
stack.offer("Gamma");
System.out.print(stack.pop() + " ");
System.out.print(stack.peek() + " ");
System.out.print(stack.poll());

What is the output of this program?

A

Gamma Beta Alpha

B

Beta Alpha Alpha

C

Beta Alpha Gamma

D

Alpha Beta Gamma

Test Your Knowledge

Which of the following code snippets compiles successfully but throws an IllegalArgumentException at runtime?

A

Set<String> set = Set.of("apple", "banana", "apple");

B

List<String> list = Arrays.asList("apple", "banana"); list.add("cherry");

C

List<String> list = List.of("apple", null, "banana");

D

Deque<String> deque = new ArrayDeque<>(); deque.add(null);

Sections you finish are checked off in the contents.