skip to content
everything.collections.theBigPicture

the big picture

the interface family tree, from Iterable down to SequencedMap.

chapter
chapter 06.01
reading time
7 min read

the java.util package is a small set of interfaces (what a collection can do) and a few implementations (how it's actually stored). List, Set and Queue all extend Collection. Map is its own family.

since java 21, the sequenced interfaces give every ordered collection the same getFirst(), getLast() and reversed().

the picture

you know how there are like forty classes in java.util and they all kinda sound the same? ArrayList, ArrayDeque, LinkedList, LinkedHashSet. it's less chaos than it looks.

think of a hiring board. the interfaces are job descriptions ("must keep things in order", "must never hold two of the same thing"). the classes are the people hired for those jobs, each with a different way of getting it done (an array, a chain of nodes, a tree). you write your code against the job description, and you can swap the hire later.

not a CollectionIterableCollectionSequencedCollection21ListSetSequencedSet21SortedSetNavigableSetQueueDequeMapSequencedMap21SortedMapNavigableMap
implementations · click one to light up everything it is
List<E>since java 1.2extends SequencedCollection

ordered by index. duplicates welcome.

addsget(i)set(i, e)add(i, e)remove(i)indexOf(o)subList(a, b)sort(cmp)listIterator()
implemented by ArrayList, LinkedList
click an interface to see what it adds and who implements it. click a class at the bottom to light up every interface it is. notice Map sits alone, and the three Sequenced ones (java 21) slot in between.

read the arrows as "is a". a Deque is a Queue and also a SequencedCollection. a NavigableSet is a SortedSet is a SequencedSet is a Set is a Collection is an Iterable. that last one is why every collection works in a for-each loop (the loop just asks for an iterator, more in iterators and fail-fast).

four shapes of data

forget the class names for a second. almost every collection you'll ever need is one of four shapes.

List
abac0123get(2) → a
by position. duplicates fine.
Set
bacaadd(a) → false
no duplicates. that's the whole job.
Deque
xyzfirstlast
in and out at either end.
Map
ada36bob41eve36
unique keys, each to one value.
the four shapes. a List cares about position, a Set cares about uniqueness, a Deque cares about its ends, a Map cares about keys.

and then each shape has a couple of ways to be stored. that's where the real differences live: speed, memory, ordering.

classis ainsidechapter
ArrayListListan Object[] that growsArrayList
LinkedListList, Dequedoubly linked nodesLinkedList and ArrayDeque
ArrayDequeDequea circular Object[]LinkedList and ArrayDeque
PriorityQueueQueuea binary heap in an Object[]PriorityQueue
HashMapMapan array of bucketsHashMap
LinkedHashMapSequencedMapa HashMap with a linked list through itLinkedHashMap
TreeMapNavigableMapa red-black treeTreeMap
HashSet, TreeSetSet, NavigableSeta HashMap / TreeMap with dummy valuessets
EnumSetSetbits in a longsets

see the pattern? there are really only four storage tricks in here: a flat array, linked nodes, a hash table and a balanced tree. every class is one of those (or two of them glued together).

quick check
which of these can you call getFirst() on, in java 21+?

sequenced collections java 21+

here's a fun one. before java 21, "give me the last element" was spelled differently for every collection:

don'tbefore 21: four ways to say last
java
list.get(list.size() - 1);
deque.getLast();
sortedSet.last();
// LinkedHashSet: walk the whole thing
String last = null;
for (String s : linkedSet) last = s;
do21+: one way
java
list.getLast();
deque.getLast();
sortedSet.getLast();
linkedSet.getLast();

JEP 431 added three interfaces: SequencedCollection, SequencedSet and SequencedMap. anything with a defined encounter order got getFirst, getLast, addFirst, addLast, removeFirst, removeLast and reversed() (maps got firstEntry, lastEntry, putFirst, putLast and friends).

Main.java
void main() {
    List<String> list = new ArrayList<>(List.of("a", "b", "c"));
    Deque<String> deque = new ArrayDeque<>(List.of("a", "b", "c"));
    SequencedSet<String> set = new LinkedHashSet<>(List.of("a", "b", "c"));
    SequencedMap<String, Integer> map = new TreeMap<>(Map.of("a", 1, "b", 2, "c", 3));
 
    IO.println(list.getLast() + " " + deque.getLast() + " " + set.getLast() + " " + map.lastEntry());
    IO.println(list.reversed() + " " + set.reversed() + " " + map.reversed());
}
output
c c c c=3
[c, b, a] [c, b, a] {c=3, b=2, a=1}

(no imports: a compact source file gets all of java.base imported for free, java.util included.)

predict the output
java
List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
List<Integer> r = list.reversed();
list.add(4);
IO.println(r);

program to the interface

declare the variable as the job, not the hire:

java
List<String> names = new ArrayList<>();     // the type says "a list"
Map<String, Integer> ages = new HashMap<>(); // the type says "a map"

now every method that takes names only promises to use list things. if a profiler later tells you a different implementation fits better, you change one new and nothing else.

but pick the right interface. Collection is the most flexible type and the least useful one: it has no get(i), no order and no idea about keys. take the narrowest thing that has the methods you actually call.

the legacy ones

Vector, Hashtable, Stack and Enumeration are from java 1.0, before the collections framework existed (it arrived in 1.2). they still compile, they still work, and they make every single method synchronized, which costs you on every call and still doesn't make compound actions like "check then add" safe.

legacyuse instead
VectorArrayList
StackArrayDeque (push / pop / peek)
HashtableHashMap, or ConcurrentHashMap if threads share it
EnumerationIterator

if you really need thread-safety, reach for the concurrent collections, which were designed for it instead of patched for it.

keylines
  • interfaces say what a collection can do. classes say how it's stored.
  • List, Set, Queue, Deque are Collections. Map is its own family.
  • four storage tricks underneath everything: array, linked nodes, hash table, balanced tree.
  • java 21 gave every ordered collection getFirst, getLast and reversed().
  • declare the interface, new the class. skip Vector, Stack and Hashtable.