skip to content

Collections Utility & Factories

The Collections static helpers and the modern List.of and Map.of factories, including the difference between an unmodifiable view and a genuinely immutable collection. That difference is the question interviewers actually ask.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

10

What is the java.util.Collections class, and how does it differ from the Collection interface?

level: juniorimportance: must knowfreq 70%

answer

  1. Collection = interface, Collections = static toolbox
  2. Mirror of Arrays for plain arrays
  3. final class, private ctor, all static
  4. sort/reverse/shuffle, unmodifiable/synchronized, empty/singleton

basics

~10 s

Collection (no 's') is the interface that lists and sets implement. Collections (with 's') is a helper class full of static methods like sort, reverse, and emptyList that operate on those collections.

solid answer

~30 s

java.util.Collection is the root interface of the collections hierarchy (List, Set, Queue all extend it). java.util.Collections is a separate utility class that only holds static helper methods and constants; you never instantiate it. Its methods take a collection as an argument and do something useful: sort and binarySearch on lists, reverse and shuffle, unmodifiableList and synchronizedMap wrappers, and factories like emptyList and singletonList. The naming is a classic Java gotcha because the two are unrelated types that differ only by an 's'. Collections sits beside Arrays, which plays the same utility role for plain arrays.

go deeper

for a junior

Knows Collections is a helper class with static methods (sort, reverse) and that it is not the same as the Collection interface.

for a middle

Explains the utility-class pattern (final, private ctor, static), and names the wrapper/factory families alongside the algorithms.

for a senior

Articulates why the class exists historically (no interface default methods pre-Java 8) and contrasts it with Arrays and with Stream-based alternatives.

for a principal

Frames it as a design-pattern example, discusses migration toward List.of/Stream APIs, and the legacy/compat tradeoffs of keeping these wrappers.

## The two confusingly named types Java has two types whose names differ by a single letter, and they do completely different jobs: - **`java.util.Collection`** (singular) is an **interface** — the root of the collections type hierarchy. `List`, `Set`, and `Queue` all extend it; `ArrayList`, `HashSet`, etc. ultimately implement it. An interface defines *what operations a collection supports* (add, remove, size, iterator) without saying how. - **`java.util.Collections`** (plural) is a **utility class** — a `final` class with a `private` constructor, so you can never create an instance of it. It contains only `static` methods (and a few constants). A static method belongs to the class itself, so you call it as `Collections.sort(list)`, not on an object. The relationship is: `Collections` is a toolbox *for* working with `Collection` objects. It is the exact analogue of `java.util.Arrays`, which is the toolbox for plain arrays. ## What lives in Collections The class groups several families of helpers: 1. **Algorithms on `List`:** `sort(list)`, `sort(list, comparator)`, `binarySearch(list, key)`, `reverse(list)`, `shuffle(list)`, `swap`, `fill`, `max`, `min`, `frequency`, `rotate`. 2. **Read-only (unmodifiable) wrappers:** `unmodifiableList`, `unmodifiableSet`, `unmodifiableMap` — return a view that throws `UnsupportedOperationException` on any mutating call. 3. **Thread-safe (synchronized) wrappers:** `synchronizedList`, `synchronizedSet`, `synchronizedMap` — wrap each method in a lock. 4. **Empty / singleton factories:** `emptyList()`, `emptySet()`, `emptyMap()`, `singletonList(x)`, `singleton(x)`, `singletonMap(k,v)` — tiny immutable collections. ## Why a separate utility class at all? Before Java 8 introduced default methods, an interface could not carry implemented behavior. So shared algorithms that work on *any* `List` (like sorting) had to live somewhere external — a static utility class was the answer. `Collections` (1998, Java 1.2) is one of the oldest examples of this pattern. ## Key terms defined - **Static method:** a method called on the class, not an instance. - **Utility class:** a class that exists only to hold static helpers; not meant to be instantiated. - **Interface:** a contract of method signatures a type promises to implement. - **View / wrapper:** an object that delegates to an underlying collection rather than copying it; changes to the original are visible through the view. ## The practical takeaway When you want to *do something to* a list or set — sort it, make it read-only, get an empty one — reach for `Collections.xxx(...)`. When you want to *describe* what a parameter accepts, type it as `Collection<T>` (the interface).

  • Can you instantiate Collections?
    No. It is a final class with a private constructor; every member is static, so you only ever call Collections.xxx(...).
  • What is the array equivalent of Collections?
    java.util.Arrays — it provides Arrays.sort, Arrays.asList, Arrays.binarySearch, etc. for plain arrays.

saying these in an interview costs you the question

  • Thinking Collections is the parent interface of List/Set
  • Trying to `new Collections()`
  • Confusing Collections.sort with Stream.sorted (different APIs)

context

open as a page

What are the Java 9+ List.of, Set.of, and Map.of factory methods, and why were they introduced?

level: juniorimportance: must knowfreq 72%

basics

~10 s

They are static methods added in Java 9 that build small, unchangeable collections in one line, like List.of(1, 2, 3). The returned collection cannot be added to, removed from, or modified.

open as a page

How do Collections.sort and Collections.binarySearch work, and what are their requirements and complexity?

level: middleimportance: must knowfreq 65%

basics

~10 s

Collections.sort(list) orders a list ascending, either by the elements' natural order or by a Comparator you pass. Collections.binarySearch(list, key) finds an element quickly, but only works if the list is already sorted.

open as a page

How do List.of / Set.of / Map.of differ from Collections.unmodifiableList / unmodifiableSet / unmodifiableMap?

level: middleimportance: must knowfreq 74%

basics

~20 s

The factory methods create a brand-new collection that is truly immutable and copies nothing live. The Collections.unmodifiable* methods only wrap an existing collection in a read-only view, so if the original changes, the view changes too.

open as a page

What are the Collections.emptyList and singletonList factories, and why are they useful?

level: juniorimportance: should knowfreq 45%

basics

~10 s

Collections.emptyList() gives you a shared, immutable empty list, and singletonList(x) gives an immutable one-element list. They are handy lightweight return values when you'd otherwise create a tiny list, and they can't be modified.

open as a page

What are the null-element and duplicate-element rules of List.of / Set.of / Map.of, and how do they differ from ArrayList/HashSet/HashMap?

level: middleimportance: should knowfreq 58%

basics

~20 s

The factory methods refuse nulls: any null element, key, or value throws NullPointerException. Set.of and Map.of also throw IllegalArgumentException if you pass duplicate elements or duplicate keys. Standard ArrayList/HashSet/HashMap allow one null and silently ignore duplicates.

open as a page

What do the Collections.synchronizedXxx wrappers provide, what are their limits, and when would you prefer the java.util.concurrent collections?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Collections.synchronizedList/Map wrap a collection so each single method call is thread-safe via an internal lock. But iterating still needs you to lock manually, and a single global lock is slow under load, so concurrent collections like ConcurrentHashMap are usually better.

open as a page

What does Collections.unmodifiableList return, and how is it different from a truly immutable collection like List.of?

level: seniorimportance: should knowfreq 55%

basics

~20 s

It returns a read-only view of an existing list: you cannot add or remove through it, but the original list can still be changed and those changes show up. List.of is a separate, fully immutable copy that nobody can change.

open as a page

Why do List.of / Set.of / Map.of have many fixed-arity overloads plus a varargs form, and how do you build a larger immutable Map?

level: seniorimportance: should knowfreq 42%

basics

~20 s

They provide overloads for 0 to 10 elements so small collections avoid creating an array, which saves memory and speeds things up. For bigger collections there is a varargs version, and for large maps you use Map.entry plus Map.ofEntries.

open as a page

Are collections from List.of / Map.of deeply immutable, and what does that mean for stored mutable objects and thread safety?

level: seniorimportance: should knowfreq 48%

basics

~20 s

They are only shallowly immutable. You cannot add, remove, or replace elements, but if an element is itself a mutable object (like an ArrayList or a bean), you can still change that object's internal state. The collection structure is fixed; the contents' internals are not protected.

open as a page