Java Collections Utility Class: sort, shuffle, unmodifiable, and more
java.util.Collections (note: not the Collection interface) is a utility class full of static methods for manipulating collections: sorting, searching, shuffling, reversing, finding min/max, counting, rotating, and creating various wrappers. These utilities prevent you from reinventing common operations and make intent clear. Knowing the full palette saves time and produces more readable code.
Contents
sort, reverse, binarySearch
Collections.sort()reverse()binarySearch()
import java.util.*;
List<Integer> nums = new ArrayList<>(List.of(3, 1, 4, 1, 5, 9, 2, 6));
// sort — stable, O(n log n)
Collections.sort(nums);
System.out.println(nums); // [1, 1, 2, 3, 4, 5, 6, 9]
// sort with Comparator
Collections.sort(nums, Comparator.reverseOrder());
System.out.println(nums); // [9, 6, 5, 4, 3, 2, 1, 1]
// reverse — reverses current order (not the same as sort descending)
Collections.reverse(nums);
System.out.println(nums); // [1, 1, 2, 3, 4, 5, 6, 9] — reversed back
// binarySearch — list MUST be sorted ascending; returns index or (-(insertion point) - 1)
Collections.sort(nums);
int idx = Collections.binarySearch(nums, 5);
System.out.println(idx); // e.g. 5 (index of value 5)
int missing = Collections.binarySearch(nums, 7);
System.out.println(missing); // negative (not found)
// binarySearch with Comparator — list must be sorted with same Comparator
List<String> words = new ArrayList<>(List.of("Apple", "banana", "Cherry"));
Collections.sort(words, String.CASE_INSENSITIVE_ORDER);
int pos = Collections.binarySearch(words, "cherry", String.CASE_INSENSITIVE_ORDER);
System.out.println(pos); // found index
// rotate — rotates elements by distance positions
List<Integer> r = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Collections.rotate(r, 2); // right-rotate by 2
System.out.println(r); // [4, 5, 1, 2, 3]
shuffle, fill, copy, nCopies
shuffle()Randomfill()nCopies()copy()
List<Integer> deck = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
// shuffle — randomizes in-place using default Random (or supplied Random for reproducibility)
Collections.shuffle(deck);
System.out.println(deck); // random order
Collections.shuffle(deck, new Random(42)); // seeded — reproducible shuffle
// fill — replace all elements with a single value
List<String> grid = new ArrayList<>(Collections.nCopies(9, "")); // 9 empty strings
Collections.fill(grid, "X");
System.out.println(grid); // [X, X, X, X, X, X, X, X, X]
// nCopies — immutable list with n copies of an object
List<Integer> zeros = Collections.nCopies(5, 0);
System.out.println(zeros); // [0, 0, 0, 0, 0]
// Useful for pre-populating or initializing arrays
// copy — copies src elements into dest (dest must be at least as large as src)
List<Integer> src = List.of(10, 20, 30);
List<Integer> dest = new ArrayList<>(Collections.nCopies(5, 0));
Collections.copy(dest, src); // dest[0..2] = src[0..2]
System.out.println(dest); // [10, 20, 30, 0, 0]
// swap — swap two elements by index
List<String> letters = new ArrayList<>(List.of("a", "b", "c", "d"));
Collections.swap(letters, 0, 3);
System.out.println(letters); // [d, b, c, a]
// replaceAll — replace all occurrences of oldVal with newVal
List<String> data = new ArrayList<>(List.of("a", "b", "a", "c", "a"));
Collections.replaceAll(data, "a", "X"); // not the same as List.replaceAll(UnaryOperator)
System.out.println(data); // [X, b, X, c, X]
min, max, frequency, disjoint
Collections.min()max()Comparatorfrequency()disjoint()true
List<Integer> values = List.of(3, 1, 4, 1, 5, 9, 2, 6, 5, 5);
// min and max — uses natural order (or Comparator)
System.out.println(Collections.min(values)); // 1
System.out.println(Collections.max(values)); // 9
// With Comparator
List<String> words = List.of("fig", "apple", "banana");
System.out.println(Collections.min(words, Comparator.comparingInt(String::length))); // "fig"
System.out.println(Collections.max(words, Comparator.comparingInt(String::length))); // "banana"
// frequency — count occurrences of an element
System.out.println(Collections.frequency(values, 5)); // 3
System.out.println(Collections.frequency(values, 7)); // 0
// disjoint — true if no element in common
List<Integer> a = List.of(1, 2, 3);
List<Integer> b = List.of(4, 5, 6);
List<Integer> c = List.of(3, 4, 5);
System.out.println(Collections.disjoint(a, b)); // true — no common elements
System.out.println(Collections.disjoint(a, c)); // false — 3 is in both
// Works with any two Collection types
Set<String> set = Set.of("x", "y");
List<String> list = List.of("a", "b", "x");
System.out.println(Collections.disjoint(set, list)); // false — "x" in common
// Practical: count word frequencies in a list
List<String> tokens = List.of("the", "cat", "sat", "on", "the", "mat", "the");
Set<String> unique = new HashSet<>(tokens);
unique.forEach(w -> System.out.println(w + ": " + Collections.frequency(tokens, w)));
// For large datasets, use a HashMap counter instead — O(n) vs O(n * unique)
Unmodifiable Wrappers
Collections.unmodifiableList()UnsupportedOperationExceptionList.copyOf()
// Collections.unmodifiable* — read-only view of a collection
// Mutations throw UnsupportedOperationException
List<String> mutable = new ArrayList<>(List.of("a", "b", "c"));
List<String> readOnly = Collections.unmodifiableList(mutable);
System.out.println(readOnly.get(0)); // "a" — reads work
// readOnly.add("d"); // UnsupportedOperationException
// IMPORTANT: the view is backed by the original — changes to mutable show in readOnly
mutable.add("d");
System.out.println(readOnly.size()); // 4 — sees the change!
// For a true immutable snapshot, use List.copyOf() (Java 10+) or List.of()
List<String> snapshot = List.copyOf(mutable); // independent copy, immutable
// Other unmodifiable wrappers
Set<String> uSet = Collections.unmodifiableSet(new HashSet<>());
Map<String, Integer> uMap = Collections.unmodifiableMap(new HashMap<>());
SortedSet<String> uSSet = Collections.unmodifiableSortedSet(new TreeSet<>());
SortedMap<String,?> uSMap = Collections.unmodifiableSortedMap(new TreeMap<>());
// Singleton collections — single-element immutable collections
List<String> one = Collections.singletonList("only");
Set<String> ons = Collections.singleton("only");
Map<String, Integer> onm = Collections.singletonMap("key", 42);
// emptyList/emptySet/emptyMap — canonical immutable empty collections
List<String> empty = Collections.emptyList(); // type-safe, no allocation
// Prefer List.of(), Set.of(), Map.of() for modern code (Java 9+)
List.of()Set.of()Map.of()Collections.unmodifiableList()Synchronized Wrappers
Collections.synchronizedList()synchronizedjava.util.concurrent
// Collections.synchronized* — wrap any collection for thread-safety
// Every method is synchronized on the wrapper object
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
syncList.add("item1"); // thread-safe add
syncList.add("item2");
// CRITICAL: iteration must be manually synchronized!
synchronized (syncList) {
for (String s : syncList) { // safe — holds the lock
System.out.println(s);
}
}
// Without the synchronized block, another thread could modify syncList during iteration
// Other synchronized wrappers
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
// Modern alternative — prefer java.util.concurrent classes for new code
// CopyOnWriteArrayList — thread-safe, iteration doesn't need external sync
// (good for read-heavy, infrequent-write scenarios)
import java.util.concurrent.*;
List<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("a");
cowList.add("b");
for (String s : cowList) { // safe — iterates over a snapshot
System.out.println(s);
}
// ConcurrentHashMap — better than synchronizedMap for concurrent access
Map<String, Integer> concMap = new ConcurrentHashMap<>();
concMap.put("a", 1);
concMap.computeIfAbsent("b", k -> 2); // atomic operation
Collectionsjava.util.concurrentConcurrentHashMapCopyOnWriteArrayListBlockingQueue