Core Interfaces
List, Set, Map, Queue and Deque interfaces
The Java Collections Framework defines a hierarchy of interfaces â List, Set, Map, Queue, Deque â each representing a distinct contract for storing and accessing data.
1. Definition
What is it?
The Java Collections Framework (JCF) is a unified architecture for representing and manipulating groups of objects. At its core are a set of interfaces that define the contracts â the what, not the how â of different collection types.
Why does it exist?
Before JCF (pre-Java 1.2), Java had only Vector, Stack, Hashtable, and arrays â each with inconsistent APIs. JCF introduced a coherent hierarchy so that:
- Algorithms can be written against interfaces, not concrete classes
- Implementations are interchangeable without breaking callers
- Common operations (iteration, sorting, filtering) work uniformly
Where does it fit?
Main interface hierarchy summary:
Iterablesits at the top.CollectionextendsIterable.Listis the ordered branch and allows duplicates.Setis the no-duplicates branch, withSortedSetandNavigableSetvariants.Queuecovers FIFO or priority-oriented access, withDequeas the double-ended variant.Mapis a separate key-value hierarchy, withSortedMapandNavigableMapas ordered variants.
2. Core Concepts
2.1 `Collection` â the root interface
The root of the collection hierarchy (excluding Map). Provides:
add(E e),remove(Object o),contains(Object o)size(),isEmpty(),clear()iterator(),forEach(),stream()- Bulk operations:
addAll,removeAll,retainAll,containsAll
2.1.1 Keywords and terms that must be understood precisely here
In this topic, it is not enough to memorize implementation names. The following keywords and concepts must be understood precisely:
interfaceâ defines a contract, not a concrete storage strategy.extendsâ an interface can extend another interface, for exampleCollectionextendsIterable.implementsâ a concrete class fulfills an interface contract, for exampleArrayListimplementsList.Iterableâ guarantees that a structure can be traversed withfor-each.Collectionâ the common base for most element-based collections, whileMapis outside that hierarchy.Listâ order and position are part of the contract.Setâ uniqueness is part of the contract.Mapâ a key-value association and a separate hierarchy.Queue/Dequeâ express access semantics, not just storage.
That is why in interviews and API design you should always state which word implies which contract, instead of merely saying "this is a collection".
2.2 `List` â ordered, index-accessible
| Property | Details |
|---|---|
| Order | Insertion order preserved |
| Duplicates | â Allowed |
| Index access | â
get(int index) |
| Null elements | â Usually allowed |
| Key implementations | ArrayList, LinkedList, CopyOnWriteArrayList |
Key additional methods: get(int), set(int, E), add(int, E), remove(int), indexOf(Object), subList(from, to), sort(Comparator).
2.3 `Set` â no duplicates
| Property | Details |
|---|---|
| Order | Depends on implementation (none/insertion/sorted) |
| Duplicates | â Not allowed (determined by equals/hashCode) |
| Index access | â No get(int) |
| Null elements | â At most one null |
| Key implementations | HashSet, LinkedHashSet, TreeSet |
SortedSet adds: first(), last(), headSet(to), tailSet(from), subSet(from, to).
NavigableSet adds: floor(e), ceiling(e), lower(e), higher(e), descendingSet().
2.4 `Queue` â FIFO access
| Operation | Throws exception | Returns special value |
|---|---|---|
| Insert | add(e) |
offer(e) â false |
| Remove head | remove() |
poll() â null |
| Examine head | element() |
peek() â null |
Key implementations: LinkedList, ArrayDeque, PriorityQueue.
2.5 `Deque` â double-ended queue (extends Queue)
Allows insertion/removal at both ends. Also usable as a Stack (LIFO).
| Operation | Front | Back |
|---|---|---|
| Insert | addFirst(e) / offerFirst(e) |
addLast(e) / offerLast(e) |
| Remove | removeFirst() / pollFirst() |
removeLast() / pollLast() |
| Examine | peekFirst() |
peekLast() |
| Stack use | push(e) = addFirst |
pop() = removeFirst |
Key implementations: ArrayDeque (preferred), LinkedList.
2.6 `Map` â key-value pairs
Map does not extend Collection. Key operations:
put(K, V),get(K),remove(K),containsKey(K),containsValue(V)keySet()âSet<K>,values()âCollection<V>,entrySet()âSet<Map.Entry<K,V>>- Java 8+:
getOrDefault,putIfAbsent,computeIfAbsent,merge,forEach
SortedMap adds: firstKey(), lastKey(), headMap(to), tailMap(from), subMap(from, to).
2.7 Iteration order and traversal guarantees
The interface choice also determines what you can safely assume about iteration.
Listguarantees stable positional traversal orderHashSetandHashMapdo not guarantee iteration orderLinkedHashSetandLinkedHashMappreserve insertion orderTreeSetandTreeMapiterate in comparator orderPriorityQueuereturns priority order throughpoll(), but not through arbitrary iteration
This is especially important in tests, logging, serialization, and UI output.
2.8 Read-only views vs immutable collections
Collections can also differ by mutation contract:
Collections.unmodifiableList(list)returns a read-only viewList.of(...)returns an immutable collectionList.copyOf(...)returns an immutable snapshot copy
These distinctions are part of API design, not just syntax.
3. Practical Usage
When to use which interface?
| Scenario | Interface | Why |
|---|---|---|
| Ordered list of items, index access needed | List |
O(1) positional access |
| Unique elements, fast membership test | Set |
contains in O(1) (HashSet) |
| Key â value lookup | Map |
O(1) lookup by key |
| Task queue / event processing | Queue |
FIFO semantics |
| Undo/redo stack, browser history | Deque |
Both ends accessible |
| Sorted elements, range queries | SortedSet / SortedMap |
Natural or custom order |
Code to interface, not implementation
// â
Program to interface
List<String> names = new ArrayList<>();
Map<String, Integer> scores = new HashMap<>();
// â Over-specifying implementation
ArrayList<String> names = new ArrayList<>(); // loses flexibility
When NOT to use Collections
- Fixed-size numeric data with known dimensions â use primitive arrays
- Concurrent updates with high contention â use
java.util.concurrenttypes directly - Stream pipeline intermediate results â don't collect prematurely
Quick API design checklist
When exposing collections in an API, ask:
- Is ordering part of the contract?
- Are duplicates meaningful?
- Do callers need index access?
- Do callers need membership checks?
- Should the caller be able to mutate the result?
Those answers usually point to the smallest correct interface.
4. Code Examples
Basic Example â Interface contracts in action
import java.util.*;
public class InterfaceContracts {
public static void main(String[] args) {
// List â order preserved, duplicates allowed
List<String> list = new ArrayList<>(List.of("banana", "apple", "apple", "cherry"));
System.out.println(list); // [banana, apple, apple, cherry]
System.out.println(list.get(1)); // apple
// Set â no duplicates, iteration order not guaranteed (HashSet)
Set<String> set = new HashSet<>(list);
System.out.println(set.size()); // 3 (apple deduplicated)
// Queue â FIFO
Queue<String> queue = new LinkedList<>(List.of("first", "second", "third"));
System.out.println(queue.poll()); // first
System.out.println(queue.peek()); // second
// Deque as stack â LIFO
Deque<String> stack = new ArrayDeque<>();
stack.push("a"); stack.push("b"); stack.push("c");
System.out.println(stack.pop()); // c (LIFO)
// Map â key-value
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 90); map.put("Bob", 85);
System.out.println(map.get("Alice")); // 90
System.out.println(map.getOrDefault("Charlie", 0)); // 0
}
}
Advanced Example â Writing generic algorithms against interfaces
public class CollectionUtils {
// Works with ANY List implementation
public static <T extends Comparable<T>> T findMax(List<T> list) {
if (list.isEmpty()) throw new NoSuchElementException();
T max = list.get(0);
for (T item : list) {
if (item.compareTo(max) > 0) max = item;
}
return max;
}
// Works with ANY Collection
public static <T> void printAll(Collection<T> collection) {
collection.forEach(System.out::println);
}
// Returns unmodifiable view â callers get List contract only
public static List<String> getNames() {
List<String> names = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));
return Collections.unmodifiableList(names);
}
}
Common Pitfall â Mutating while iterating
List<String> items = new ArrayList<>(List.of("a", "b", "c", "b"));
// â ConcurrentModificationException!
for (String s : items) {
if (s.equals("b")) items.remove(s);
}
// â
Use Iterator's remove()
Iterator<String> it = items.iterator();
while (it.hasNext()) {
if (it.next().equals("b")) it.remove();
}
// â
Or use removeIf (Java 8+)
items.removeIf(s -> s.equals("b"));
5. Trade-offs
| Interface | ⥠Access Speed | đŸ Memory | đ§ Features | Use Case |
|---|---|---|---|---|
List |
O(1) index (array), O(n) search | Moderate | Index, sort, subList | Ordered sequences |
Set |
O(1) contains (hash), O(log n) (tree) | LowâModerate | Uniqueness | Membership test, deduplication |
Queue |
O(1) head operations | Low | FIFO semantics | Task scheduling |
Deque |
O(1) both ends | Low | Stack + Queue | Undo, sliding window |
Map |
O(1) by key (hash), O(log n) (tree) | ModerateâHigh | Key-value, merge ops | Caching, indexing |
6. Common Mistakes
1. Using `List` when uniqueness matters
// â Allows duplicates â bug if you need unique items
List<String> tags = new ArrayList<>();
tags.add("java"); tags.add("java"); // silent duplicate
// â
Use Set
Set<String> tags = new HashSet<>();
tags.add("java"); tags.add("java"); // size stays 1
2. Using `Stack` class (legacy)
// â Stack extends Vector â synchronized, legacy, avoid!
Stack<Integer> stack = new Stack<>();
// â
Use Deque
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1); stack.pop();
3. Ignoring `null` behavior differences
// TreeSet/TreeMap: null throws NullPointerException
TreeSet<String> sorted = new TreeSet<>();
sorted.add(null); // â NullPointerException â can't compare null
// HashSet: allows one null
HashSet<String> hashed = new HashSet<>();
hashed.add(null); // â
OK
4. Calling `remove(Object)` vs `remove(int)` on List
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 4));
numbers.remove(1); // removes by INDEX â [1, 3, 4]
numbers.remove(Integer.valueOf(3)); // removes by VALUE â [1, 4]
7. Deep Dive
Interface segregation in API design
Return the narrowest useful type from your methods. If callers only need to iterate, return Iterable<T>. If they need to check membership, return Collection<T>. Only return List if index access is truly needed.
`Iterable` vs `Collection` vs `List`
Iterable â can iterate (for-each)
Collection â + size, contains, add, remove
List â + index access, sort
Each step adds overhead (memory, complexity) â choose the minimum contract.
`Collections.unmodifiableXxx` vs `List.of` / `Set.of`
Collections.unmodifiableList(list)â view of a mutable list; underlying changes are visible!List.of(...)(Java 9+) â truly immutable; throws on any mutation attemptList.copyOf(collection)(Java 10+) â immutable copy, snapshot semantics
Performance implications of interface choice
Passing a LinkedList to a method that calls get(int) repeatedly is O(nÂČ). Accepting List<T> in your API doesn't guarantee random access â consider accepting RandomAccess marker or documenting requirements.
`SortedSet` and `SortedMap` consistency
The comparator must be consistent with equals: if comparator.compare(a, b) == 0 then a.equals(b) should be true. Otherwise, the Set contract (no duplicates) breaks silently.
Live views are not immutable snapshots
List<String> source = new ArrayList<>(List.of("a", "b"));
List<String> view = Collections.unmodifiableList(source);
source.add("c");
System.out.println(view); // [a, b, c]
This is a read-only wrapper, not a frozen copy.
Narrow return types reduce coupling
If callers only need traversal, returning Iterable<T> can be more honest than returning List<T>. The narrower the contract, the easier it is to change the implementation later.
8. Interview Questions
Why does `Map` not extend `Collection`?
Because a map models key-value associations rather than a plain group of elements, so its core operations and semantics are different.
When would you return `Iterable`, `Collection`, or `List`?
Return the narrowest type that still supports the callerâs needs: Iterable for traversal, Collection for size and membership, and List only when ordering plus positional access matter.
What is the practical difference between `Queue` and `Deque`?
Queue models one-ended head/tail processing, while Deque allows efficient operations at both ends and can also replace the legacy stack use case.
Why can a `TreeSet` reject something that looks like a distinct value?
Because uniqueness is defined by ordering equivalence. If the comparator says two elements compare as zero, the set treats them as the same slot.
9. Glossary
| Term | Definition |
|---|---|
| JCF | Java Collections Framework â the unified hierarchy of collection interfaces and implementations |
| Contract | The behavioral guarantee an interface makes to its callers |
| RandomAccess | Marker interface on ArrayList etc. indicating O(1) index access |
| FIFO | First-In-First-Out â insertion order determines removal order (Queue) |
| LIFO | Last-In-First-Out â most recently added item is removed first (Stack/Deque) |
| NavigableSet | Extension of SortedSet with methods for floor/ceiling/lower/higher queries |
| Fail-fast iterator | Iterator that throws ConcurrentModificationException if the collection is modified during iteration |
| Structural modification | Any change to the size of a collection (add/remove), as opposed to set |
10. Cheatsheet
- đ
Listâ ordered, index access, duplicates OK âArrayList(default) - đ
Setâ no duplicates, fastcontainsâHashSet(default) - đșïž
Mapâ key-value, fastgetby key âHashMap(default) - đŹ
Queueâ FIFO task processing âArrayDeque(preferred overLinkedList) - âïž
Dequeâ both ends accessible, also a stack âArrayDeque - â ïž
Stackclass is legacy â useArrayDequeinstead - â
Program to interface â
List<E>notArrayList<E>in signatures - đ Immutable collections â
List.of(),Set.of(),Map.of()(Java 9+) - đ«
TreeSet/TreeMaprejectnullkeys/elements - đ Mutate while iterating â use
iterator.remove()orremoveIf()
đź Games
10 questions