🗃️ Collections Framework · Intermediate

The Collections utility class in Java

sort, reverse, shuffle, max, frequency, unmodifiable and synchronized wrappers.

🧩 The mysteryYou hand out a read-only view of your list. Nobody can change it... yet its contents keep changing. Meet the Collections toolbox and its sneaky wrappers.

Collections, with an s

**java.util.Collections is a toolbox of static methods. sort, reverse, shuffle and swap rearrange a List in place. max, min and frequency** just read any Collection.

var list = new ArrayList<>(List.of(3, 1, 2));
Collections.sort(list);    // [1, 2, 3]
Collections.reverse(list); // [3, 2, 1]
Collections.max(list);     // 3
Collections.shuffle(list); // random order
🔮 Predict it

Your turn

What does this print?

var list = new ArrayList<>(List.of(4, 2, 9));
Collections.sort(list);
Collections.reverse(list);
System.out.println(list);
var w = List.of("x", "y", "x");
int n = Collections.frequency(w, "x");
System.out.println(n);
  1. [2, 4, 9] 1
  2. [9, 4, 2] 2
  3. [9, 2, 4] 2
Show the answer

sort gives [2, 4, 9], then reverse flips it to [9, 4, 2]. frequency counts elements equal to "x": there are 2.

Read-only wrappers are windows

**Collections.unmodifiableList(list) wraps the original without copying. Nobody can change the list *through* the wrapper, but it's a view**: changes made to the original show through.

var base = new ArrayList<>(List.of("a"));
var view = Collections.unmodifiableList(base);
view.add("b"); // throws Unsupported-
               // OperationException
base.add("b"); // allowed, and view sees it
🔮 Predict it

Peek through the window

What does this print?

var base = new ArrayList<>(List.of("a"));
var view = Collections.unmodifiableList(base);
base.add("b");
System.out.println(view);
  1. [a]
  2. [a, b]
  3. Throws UnsupportedOperationException
Show the answer

base.add is allowed, and the view looks at the same underlying list, so it shows [a, b].

⚠️ The trap

Sorting a read-only list

Collections.sort(ro) tries to rearrange the list it's given. If ro is unmodifiable, it throws **UnsupportedOperationException at runtime**. The compiler can't warn you: ro is just a List.

var data = new ArrayList<>(List.of(2, 1));
var ro = Collections.unmodifiableList(data);
Collections.sort(ro); // throws at runtime

Synchronized wrappers

**Collections.synchronizedList(list) locks every single call. But iterating is many calls, so the Javadoc says you must lock manually** around the loop.

var sync = Collections.synchronizedList(list);
synchronized (sync) {
    for (var x : sync) { use(x); }
}
💼 In the real world

On the job

Getters often return Collections.unmodifiableList(items) to protect internal state. Remember callers still see your later changes. Want a frozen snapshot instead? That's List.copyOf, coming next. shuffle shows up in games, quizzes and A/B test sampling.

Key takeaways

  1. sort, reverse, shuffle, swap modify a List in place
  2. max, min, frequency read any Collection
  3. unmodifiableList(list) is a read-only VIEW — changes to the original show through
  4. synchronizedList still needs manual locking while iterating
🤯 Did you know?

Collections.shuffle uses the Fisher–Yates algorithm: walk the list backwards, swapping each element with a randomly chosen earlier (or same) position. Every permutation is equally likely.

Practice questions

What does this print?

var list = new ArrayList<>(List.of(3, 1, 2));
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
  1. [1, 2, 3] [3, 2, 1]
  2. [1, 2, 3] [2, 1, 3]
  3. [3, 1, 2] [2, 1, 3]
  4. [1, 2, 3] [1, 2, 3]
Check your answer

[1, 2, 3] [3, 2, 1]. sort orders the list ascending in place; reverse then flips the current order in place.

What does this print?

var words = List.of("b", "a", "c", "a");
System.out.println(Collections.max(words));
System.out.println(Collections.frequency(words, "a"));
  1. a 2
  2. c 2
  3. c 1
  4. b 2
Check your answer

c 2. max uses natural ordering, so "c" is the largest String. frequency counts elements equal to "a": there are two.

Next: List.of creates lists that can never change, and that throw if you even try to put a null inside.