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.
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
| Feature | ArrayList<E> | LinkedList<E> |
|---|---|---|
| Underlying Structure | Resizable array (Object[]) | Doubly-linked nodes (Node<E>) |
Positional Access (get/set) | constant time | linear traversal |
Append (add) | Amortized | constant time |
| Arbitrary Insert/Delete | due to System.arraycopy shift | once node is reached, but to locate index |
| Memory Footprint | Compact contiguous memory | High per-element overhead (prev/next pointers) |
| Interface Contracts | List, RandomAccess, Cloneable | List, 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
| Implementation | Ordering Guarantee | Null Policy | Underlying Data Structure | Access Time |
|---|---|---|---|---|
HashSet | No guaranteed order; can change on rehash | Allows one null | Hash table (HashMap) | lookup/add |
LinkedHashSet | Preserves element insertion order | Allows one null | Hash table + doubly-linked list | lookup/add |
TreeSet | Sorted order (natural Comparable or Comparator) | Strictly rejects null | Red-Black tree (TreeMap) | 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 thane(< e), ornull.floor(e): Greatest element less than or equal toe(<= e), ornull.ceiling(e): Least element greater than or equal toe(>= e), ornull.higher(e): Least element strictly greater thane(> e), ornull.pollFirst(),pollLast(): Retrieves and removes the lowest or highest element, or returnsnullif 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 Type | Throws Exception on Failure | Returns Special Value (false or null) |
|---|---|---|
| Insert | add(e) (throws IllegalStateException if full) | offer(e) (returns false if full) |
| Remove | remove() (throws NoSuchElementException if empty) | poll() (returns null if empty) |
| Examine | element() (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 toaddFirst(e)(inserts at head; throws exception if capacity reached).pop(): Equivalent toremoveFirst()(removes from head; throwsNoSuchElementExceptionif empty).peek(): Equivalent topeekFirst()(inspects head; returnsnullif 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
| Characteristic | List.of(...) | Arrays.asList(...) | new ArrayList<>(...) |
|---|---|---|---|
| Mutability | Completely immutable | Fixed-size (in-place replacement allowed) | Fully mutable (resizeable) |
| Null Support | Rejects null (NullPointerException) | Allows null | Allows null |
| Backing Store | Internal optimized class | Directly backed by source array | Independent heap array |
| Structural Modifications | Throws UnsupportedOperationException | Throws UnsupportedOperationException | Permitted (add, remove) |
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?
[2]
An IndexOutOfBoundsException is thrown at runtime
[3]
[1]
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?
Gamma Beta Alpha
Beta Alpha Alpha
Beta Alpha Gamma
Alpha Beta Gamma
Which of the following code snippets compiles successfully but throws an IllegalArgumentException at runtime?
Set<String> set = Set.of("apple", "banana", "apple");
List<String> list = Arrays.asList("apple", "banana"); list.add("cherry");
List<String> list = List.of("apple", null, "banana");
Deque<String> deque = new ArrayDeque<>(); deque.add(null);
Sections you finish are checked off in the contents.