Course contents

The collections hierarchy

Iterable, Collection, List, Set, Queue, Deque, Map, Java 21 sequenced collections, legacy classes, optional operations and marker interfaces.

FreeMust know for interviewsLesson15 min readWarm-upReviewed Oct 2026 · Java 21
On this page
  1. Picture it first: contracts first, engines second
  2. The element side under the hood
  3. Map is a separate hierarchy
  4. Java 21 sequenced collections
  5. Real world: optional operations and views
  6. Advanced: names, skeletons, markers and legacy classes
  7. The implementation map you should carry
  8. How to say it in the interview

🧭 What is the Java Collections hierarchy?

The Collections hierarchy is Java's set of interfaces for storing and traversing groups of objects. Iterable says "you can loop over me", Collection says "I hold elements", and subinterfaces such as List, Set, Queue and Deque add stronger promises. For example, List<Order> promises index-based order, while Set<OrderId> promises no duplicates.

For this lesson, we'll focus on the type map you should be able to draw in an interview: Iterable -> Collection -> List/Set/Queue/Deque, the sorted and navigable variants, Map as a separate hierarchy, Java 21's sequenced interfaces, the main implementations, legacy classes, skeleton classes, optional operations and RandomAccess. Interviewers ask this early because it exposes whether you understand contracts, not only class names.

Below the line (out of scope)

The 30-second answer

The Java Collections Framework is mostly an interface hierarchy. Iterable gives iterator(), Collection adds element operations like add, remove, contains and size, then List preserves positional order, Set enforces uniqueness, and Queue/Deque model removal order and both-ended access. SortedSet and NavigableSet add sorted and nearest-match operations; the map side is separate because a Map<K,V> stores key-value mappings, not individual elements. Java 21 added SequencedCollection, SequencedSet and SequencedMap so ordered collections have uniform getFirst, getLast and reversed() APIs. In practice, default to ArrayList, HashSet, HashMap and ArrayDeque, move to linked or tree variants only when you need insertion order, access order or sorted navigation, and avoid Vector, Stack and Hashtable unless you are maintaining old code.

What you’ll learn

  • Draw the Collections Framework hierarchy from Iterable to Collection, List, Set, Queue and Deque
  • Explain why Map is **not a Collection**, and how keySet, values and entrySet bridge the gap
  • Place SortedSet, NavigableSet, SortedMap and NavigableMap in the ordered part of the hierarchy
  • Describe Java 21 sequenced collections from JEP 431: SequencedCollection, SequencedSet and SequencedMap
  • Pick the main implementation families: ArrayList, HashSet, TreeSet, ArrayDeque, HashMap, LinkedHashMap, TreeMap and ConcurrentHashMap
  • Avoid legacy Vector, Stack and Hashtable, and know the difference between Collection and Collections
  • Recognize optional operations, UnsupportedOperationException, abstract skeleton classes and the RandomAccess marker

Interview radar

Asked very often: Why is Map not a Collection, and what is the difference between Collection and Collections? Senior rounds probe: Java 21 sequenced collections, optional operations, RandomAccess, and why skeleton classes like AbstractList exist. Production angle: Choosing a class because its name sounds right, then discovering it has the wrong ordering, thread-safety or mutability contract.

01Picture it first: contracts first, engines second

Think of the hierarchy like a set of job descriptions. Collection says "I am a bag of elements". List, Set, Queue and Deque add promises about order, uniqueness and removal. Implementations are the engines you hire to fulfill those promises: arrays, hash tables, linked nodes, heaps and trees.

Here is the hierarchy tree I want you to keep in your head. Notice that Map sits next to the collection hierarchy, not underneath it.

Fig. 1

The Java 21 Collections hierarchy shows Iterable above Collection, Collection branching directly to SequencedCollection, Set and Queue, with List, Deque, sequenced set types and Map drawn separately

The Java 21 Collections hierarchy shows Iterable above Collection, Collection branching directly to SequencedCollection, Set and Queue, with List, Deque, sequenced set types and Map drawn separately

Notice three things:

  • Iterable is about traversal, not storage. Anything with an iterator() can be used in an enhanced for loop.
  • Collection is about elements. It has add(E), contains(Object), remove(Object) and size().
  • Map is about associations. It has keys, values and entries, so its views are collections, but the map itself is not.

02The element side under the hood

Try it yourself first

Before reading on, classify each variable below by the strongest interface it should expose. Which one should be a List, which a Set, which a Deque, and which a Collection?

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class InterfaceChoice {
    public static void main(String[] args) {
        List<String> auditLines = new ArrayList<>();
        auditLines.add("created");
        auditLines.add("charged");
        System.out.println(auditLines.get(1));        // charged

        Set<String> processedIds = new HashSet<>();
        System.out.println(processedIds.add("evt-1")); // true
        System.out.println(processedIds.add("evt-1")); // false

        Deque<String> work = new ArrayDeque<>();
        work.addLast("parse");
        work.addLast("index");
        System.out.println(work.removeFirst());       // parse

        Collection<String> batch = auditLines;
        System.out.println(batch.size());             // 2
    }
}

auditLines is a List because index and encounter order matter. processedIds is a Set because duplicates are the bug. work is a Deque because we operate at the ends. batch is a Collection because the caller only needs "a group of strings".

Notice the design habit: expose the weakest useful interface. If a method only needs to count or iterate, accept Collection<? extends Order> or Iterable<? extends Order>. If it needs random index access, say List. If it needs removeFirst, say Deque.

Iterable and Collection

Iterable<E> has one core method: iterator(). The enhanced for loop is syntax over that method, so arrays are special-cased by the language, while collections use Iterator.

Collection<E> is the root of the element hierarchy. The JDK does not provide a direct general-purpose Collection class because "a group of elements" is too vague by itself. You normally pick a more specific subtype: List, Set, Queue or Deque.

Interface Promise Common implementations Interview shorthand
List<E> Encounter order plus integer index ArrayList, LinkedList, CopyOnWriteArrayList duplicates allowed, get(i) exists
Set<E> No duplicate elements by equals HashSet, LinkedHashSet, TreeSet, EnumSet membership and uniqueness
SortedSet<E> Set sorted by natural order or comparator TreeSet sorted iteration
NavigableSet<E> SortedSet plus nearest-match navigation TreeSet, ConcurrentSkipListSet floor, ceiling, lower, higher
Queue<E> Elements are removed in a defined order ArrayDeque, PriorityQueue, LinkedList FIFO or priority
Deque<E> Queue with both-ended operations ArrayDeque, LinkedList stack and queue replacement

A Queue does not always mean FIFO. PriorityQueue is a queue because poll() removes according to priority, not insertion order. If you mean normal FIFO in modern Java, say ArrayDeque unless you need blocking or concurrent handoff.

Sorted and navigable sets

SortedSet gives sorted iteration, first(), last(), headSet, tailSet and subSet. NavigableSet extends it with the operations interviewers like because they map to real product questions: floor(e), ceiling(e), lower(e), higher(e) and descending views.

import java.util.NavigableSet;
import java.util.TreeSet;

public class PriceBands {
    public static void main(String[] args) {
        NavigableSet<Integer> prices = new TreeSet<>();
        prices.add(99);
        prices.add(149);
        prices.add(199);

        System.out.println(prices.floor(160));   // 149
        System.out.println(prices.ceiling(160)); // 199
        System.out.println(prices.descendingSet()); // [199, 149, 99]
    }
}

The implementation here is TreeSet, backed by a red-black tree. Each navigation operation is O(log n), so for 1,000,000 elements it is about 20 comparisons, not a scan across the set.

03Map is a separate hierarchy

A Map<K,V> is not a Collection<E> because it does not contain one kind of element. It contains mappings from keys to values. There is no sensible add(E) operation for a map: should E be a key, a value, or a pair?

The bridge is through collection views:

import java.util.LinkedHashMap;
import java.util.Map;

public class MapViews {
    public static void main(String[] args) {
        Map<String, Integer> stock = new LinkedHashMap<>();
        stock.put("keyboard", 7);
        stock.put("mouse", 12);

        for (String sku : stock.keySet()) {
            System.out.println(sku);
        }
        for (Integer count : stock.values()) {
            System.out.println(count);
        }
        for (Map.Entry<String, Integer> entry : stock.entrySet()) {
            System.out.println(entry.getKey() + "=" + entry.getValue());
        }
    }
}

keySet() is a Set<K>, values() is a Collection<V>, and entrySet() is a Set<Map.Entry<K,V>>. Those are views, not usually independent snapshots. Remove from the entrySet iterator and you remove from the map.

Map interface Promise Common implementations Use when
Map<K,V> Unique keys mapped to values HashMap, LinkedHashMap, IdentityHashMap, WeakHashMap, EnumMap key lookup
SortedMap<K,V> Keys sorted by natural order or comparator TreeMap sorted key iteration
NavigableMap<K,V> SortedMap plus nearest-match entries TreeMap, ConcurrentSkipListMap ranges and floor/ceiling keys
SequencedMap<K,V> Defined encounter order with first/last entries LinkedHashMap, SortedMap family Java 21 first/last/reversed map APIs
ConcurrentMap<K,V> Atomic map operations for concurrency ConcurrentHashMap, ConcurrentSkipListMap shared mutable maps

The default map is HashMap. Use LinkedHashMap when iteration order matters, TreeMap when sorted keys or range queries matter, EnumMap when every key is an enum constant, IdentityHashMap when keys must be compared by ==, and ConcurrentHashMap when multiple threads update the map.

04Java 21 sequenced collections

Before Java 21, Java had ordered collections but no shared interface for "has a first element, has a last element, and can be reversed". List used get(0) and get(size - 1), Deque used getFirst() and getLast(), SortedSet used first() and last(), and LinkedHashSet had no cheap last-element method. JEP 431 filled that gap.

Java 21 added three interfaces:

Interface Extends Adds
SequencedCollection<E> Collection<E> getFirst, getLast, addFirst, addLast, removeFirst, removeLast, reversed()
SequencedSet<E> Set<E>, SequencedCollection<E> a set-shaped reversed() and repositioning semantics where supported
SequencedMap<K,V> Map<K,V> firstEntry, lastEntry, pollFirstEntry, pollLastEntry, putFirst, putLast, sequenced views, reversed()
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.SequencedMap;
import java.util.SequencedSet;

public class SequencedDemo {
    public static void main(String[] args) {
        SequencedSet<String> signups = new LinkedHashSet<>();
        signups.add("asha");
        signups.add("ravi");
        signups.addFirst("founder");
        System.out.println(signups.getFirst());        // founder
        System.out.println(signups.reversed());        // [ravi, asha, founder]

        SequencedMap<String, Integer> scores = new LinkedHashMap<>();
        scores.put("blue", 10);
        scores.put("green", 20);
        System.out.println(scores.firstEntry());       // blue=10
        scores.putFirst("green", 25);                 // reposition existing key
        System.out.println(scores.sequencedKeySet());  // [green, blue]
    }
}

Here is the catch: the interface can declare an operation that an implementation cannot honor. A sorted set decides position from the comparator, so new TreeSet<String>().addFirst("x") is allowed to throw UnsupportedOperationException. That brings us to optional operations.

05Real world: optional operations and views

In the real world

A bug I see in services is returning Collections.unmodifiableList(internalList) and assuming callers received a frozen snapshot. They did not. They received a read-only view. If your code later mutates internalList, the caller sees the change, and if the caller tries add, they get UnsupportedOperationException at runtime. Use List.copyOf for a snapshot and name your API contract clearly.

The collection interfaces mark some mutating methods as optional operations. An implementation that cannot support one should throw UnsupportedOperationException. That is why List.of("a").add("b"), Collections.unmodifiableList(list).remove(0), and TreeSet.addFirst(x) can fail even though the method exists on the type.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class OptionalOperations {
    public static void main(String[] args) {
        List<String> source = new ArrayList<>(List.of("draft"));
        List<String> view = Collections.unmodifiableList(source);
        List<String> snapshot = List.copyOf(source);

        source.add("approved");
        System.out.println(view);     // [draft, approved]
        System.out.println(snapshot); // [draft]

        try {
            view.add("paid");
        } catch (UnsupportedOperationException ex) {
            System.out.println("view is read-only");
        }
    }
}

This is not a type-system failure. It is a deliberate compromise in the Collections Framework, which lets one interface cover mutable, fixed-size, unmodifiable, view-backed and sorted structures. In interviews, say the operation is optional and the implementation decides whether it is supported.

06Advanced: names, skeletons, markers and legacy classes

Collection vs Collections

Collection is an interface. Collections is a utility class full of static methods: sort, binarySearch, reverse, shuffle, unmodifiableList, synchronizedMap, emptyList and so on. The plural name is not the framework; it is one helper class inside the framework.

This naming trips people because we casually say "Java collections" to mean the whole ecosystem. In code, Collection is a type you can accept as a parameter, while Collections is never instantiated.

Abstract skeleton classes

The framework includes skeletal implementations: AbstractCollection, AbstractList, AbstractSequentialList, AbstractSet, AbstractQueue and AbstractMap. They exist so custom collections can implement a few core methods and inherit the rest. For example, a read-only list can extend AbstractList and implement get(int) plus size().

import java.util.AbstractList;
import java.util.List;

public class RecentIds {
    static List<String> lastThree(List<String> ids) {
        int from = Math.max(0, ids.size() - 3);
        return new AbstractList<>() {
            @Override public String get(int index) {
                return ids.get(from + index);
            }
            @Override public int size() {
                return ids.size() - from;
            }
        };
    }

    public static void main(String[] args) {
        System.out.println(lastThree(List.of("a", "b", "c", "d"))); // [b, c, d]
    }
}

Because we did not override mutators, add and remove throw UnsupportedOperationException. That is exactly the skeleton-class pattern: implement the irreducible operations, inherit default behavior, and override more methods when performance or mutability requires it.

RandomAccess marker

RandomAccess is a marker interface: it has no methods. ArrayList implements it to say get(i) is generally constant time. LinkedList does not, because get(i) requires walking from an end.

Performance angle

The JDK uses RandomAccess to choose algorithms. Collections.rotate uses an index-swapping algorithm for small lists or lists that implement RandomAccess; for large sequential lists, it uses a different reversal-based strategy. The rule of thumb in the javadoc is concrete: implement RandomAccess if looping with get(i) is faster than looping with an iterator for typical instances.

If you write generic list code, this matters:

import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;

public class ListTraversal {
    static long sum(List<Integer> values) {
        long total = 0;
        if (values instanceof RandomAccess) {
            for (int i = 0; i < values.size(); i++) total += values.get(i);
        } else {
            for (Iterator<Integer> it = values.iterator(); it.hasNext(); ) total += it.next();
        }
        return total;
    }
}

You do not write this branch often in application code. You should know it because it explains why ArrayList is the default list and why generic algorithms sometimes check a marker interface.

Legacy classes to avoid

Vector, Stack and Hashtable came from Java 1.0, before the modern Collections Framework landed in Java 1.2. They synchronize individual methods, which sounds safe but is usually the wrong contract. Per-method locking does not make a multi-step operation atomic, and it adds lock overhead even when the collection is thread-confined.

Legacy class Modern default Why avoid it
Vector<E> ArrayList<E> synchronized methods, old API surface, rarely the right concurrency boundary
Stack<E> ArrayDeque<E> extends Vector, exposes list operations, slower and more confusing than a deque
Hashtable<K,V> HashMap<K,V> or ConcurrentHashMap<K,V> synchronized whole table, no null, old Enumeration API

Many candidates say "use Stack for stack" because the name is tempting. In modern Java, use ArrayDeque: push, pop and peek are available, it has no legacy Vector baggage, and it also handles FIFO queues with addLast and removeFirst.

Where candidates slip

Many candidates memorize implementations without naming the contract. "Use LinkedList for queues" is the classic example. LinkedList works, but it stores one node object per element and permits null, which makes poll() ambiguous. For an in-memory FIFO queue, start with ArrayDeque; move to BlockingQueue only when producers or consumers must wait across threads.

07The implementation map you should carry

Here is the practical lookup table. It is not the full JDK, but it covers the classes you will actually mention in interviews.

Need Interface to expose Default implementation Move when
Ordered sequence by index List ArrayList LinkedList only with a held ListIterator; CopyOnWriteArrayList for listener-style reads
Unique values, no order Set HashSet LinkedHashSet for insertion order, TreeSet for sorted order, EnumSet for enum constants
FIFO or LIFO ends Deque ArrayDeque blocking/concurrent queue for thread handoff
Priority removal Queue PriorityQueue sorted iteration requires TreeSet/TreeMap, not heap iteration
Key lookup Map HashMap LinkedHashMap for order/LRU, TreeMap for ranges, EnumMap for enum keys
Sorted nearest key NavigableMap TreeMap ConcurrentSkipListMap for concurrent sorted access
Shared mutable map ConcurrentMap ConcurrentHashMap ConcurrentSkipListMap if sorted keys are required
Reference-identity keys Map IdentityHashMap graph traversal, proxies, serialization handles
Weak keys Map WeakHashMap caches where key reachability should control entry lifetime

The simple option is almost always one of four: ArrayList, HashMap, HashSet, ArrayDeque. It stops being enough when the requirement says order, sorted range, priority, concurrent mutation, enum-only keys, weak reachability or reference identity. That is the decision path we cover next in Choosing the right collection.

08How to say it in the interview

When I ask this, I'm listening for the shape first. Can you draw Iterable, Collection, the four main element interfaces and the separate Map hierarchy? Then I listen for the practical defaults, the Java 21 update, and whether you avoid legacy classes without overclaiming about thread safety.

In the interview

"The hierarchy starts with Iterable, which gives iteration. Collection extends it and represents a group of elements. Under Collection, List means ordered and indexable, Set means unique, Queue means removal order, and Deque means both-ended queue operations. SortedSet and NavigableSet add sorted iteration and nearest-match methods like floor and ceiling. Map is separate because it stores key-value mappings, not single elements; its keySet, values and entrySet are collection views. Since Java 21, sequenced interfaces give ordered collections and maps common first, last and reversed operations. In practice I default to ArrayList, HashSet, HashMap and ArrayDeque, use linked or tree variants only for order or sorted navigation, and avoid Vector, Stack and Hashtable in new code."

On the whiteboard

Iterable -> Collection -> List / Set / Queue
                        -> SequencedCollection (Java 21)
List: ArrayList default, LinkedList rare, RandomAccess marker
Set: HashSet, LinkedHashSet, TreeSet
     SortedSet -> NavigableSet: floor/ceiling/lower/higher
Queue -> Deque: ArrayDeque default; PriorityQueue is priority, not sorted iteration
Map is separate: keys -> values, no add(E)
Map views: keySet(), values(), entrySet()
SortedMap -> NavigableMap; SequencedMap in Java 21
Collection = interface; Collections = static utilities
Optional ops may throw UnsupportedOperationException
Avoid Vector / Stack / Hashtable in new code
Practise this topicCollections framework: interview questions & scenarios
Further reading (8)