Skip to main content

11.5 Collections Utility Class

The java.util.Collections class is a collection of static utility methods for working with collections. It provides simple solutions for frequently needed tasks like sorting, searching, reversing, and creating unmodifiable collections.

1. Sorting and Reordering​

import java.util.*;

List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));

// Sort ascending
Collections.sort(numbers);
System.out.println(numbers); // [1, 2, 3, 5, 8, 9]

// Sort descending (with Comparator)
Collections.sort(numbers, Comparator.reverseOrder());
System.out.println(numbers); // [9, 8, 5, 3, 2, 1]

// Reverse order of elements
Collections.reverse(numbers);
System.out.println(numbers); // [1, 2, 3, 5, 8, 9]

// Shuffle randomly
Collections.shuffle(numbers);
System.out.println(numbers); // random order
Collections.shuffle(numbers, new Random(42)); // reproducible with seed

// Rotate (shift left by 2)
List<String> letters = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E"));
Collections.rotate(letters, -2); // rotate left by 2
System.out.println(letters); // [C, D, E, A, B]

// Swap two elements
Collections.swap(letters, 0, 4);
System.out.println(letters); // element at index 0 and 4 swapped

2. Searching and Statistics​

List<Integer> sorted = Arrays.asList(1, 3, 5, 7, 9, 11);

// Binary search (list must be sorted!)
int idx = Collections.binarySearch(sorted, 7);
System.out.println(idx); // 3 (index)

// Min and max
System.out.println(Collections.min(sorted)); // 1
System.out.println(Collections.max(sorted)); // 11

// Frequency of a specific element
List<String> fruits = Arrays.asList("apple", "banana", "apple", "strawberry", "apple");
System.out.println(Collections.frequency(fruits, "apple")); // 3

// Check if collection contains all elements of another
List<String> subset = Arrays.asList("apple", "strawberry");
System.out.println(fruits.containsAll(subset)); // true

3. Creating Unmodifiable (Immutable) Collections​

Creates read-only collections that cannot be modified externally. Attempting modification throws UnsupportedOperationException.

// Wrap an existing collection as unmodifiable
List<String> mutable = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> immutable = Collections.unmodifiableList(mutable);

// immutable.add("D"); // UnsupportedOperationException!
System.out.println(immutable.get(0)); // "A" (reads are fine)

Map<String, Integer> map = new HashMap<>();
map.put("one", 1); map.put("two", 2);
Map<String, Integer> readOnlyMap = Collections.unmodifiableMap(map);

Factory Methods (Java 9+)​

A more concise way to create unmodifiable collections:

// List.of - immutable list (no nulls allowed)
List<String> list = List.of("Alice", "Bob", "Charlie");
// list.add("Dave"); // throws!

// Set.of - immutable set (no duplicates, no guaranteed order)
Set<Integer> set = Set.of(1, 2, 3, 4, 5);

// Map.of - immutable map (key-value pairs)
Map<String, Integer> scoreMap = Map.of(
"Alice", 95,
"Bob", 87,
"Carol", 92
);

// Map.entry + Map.ofEntries (for more than 10 entries)
Map<String, Integer> bigMap = Map.ofEntries(
Map.entry("A", 1),
Map.entry("B", 2),
Map.entry("C", 3)
// ... no upper limit
);

4. Special-Purpose Collections​

// Empty immutable collections (return instead of null)
List<String> emptyList = Collections.emptyList();
Set<String> emptySet = Collections.emptySet();
Map<String, Integer> emptyMap = Collections.emptyMap();

// Single-element immutable collections
List<String> singleList = Collections.singletonList("only");
Set<String> singleSet = Collections.singleton("only");

// List of N copies of the same element (useful for initialization)
List<Integer> zeros = Collections.nCopies(5, 0);
System.out.println(zeros); // [0, 0, 0, 0, 0]

5. Thread-Safe Collections​

// Wrap existing collections to make thread-safe (legacy approach)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());

// Modern approach: use java.util.concurrent (recommended)
import java.util.concurrent.*;
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();

6. Lambda-Friendly Collection Utilities (Java 8+)​

List<String> names = new ArrayList<>(Arrays.asList("Alice", "Bob", "Charlie", "Dave"));

// removeIf: remove elements matching a predicate
names.removeIf(name -> name.length() < 4);
System.out.println(names); // [Alice, Charlie, Dave]

// replaceAll: transform every element in-place
names.replaceAll(String::toUpperCase);
System.out.println(names); // [ALICE, CHARLIE, DAVE]

// sort with Comparator
names.sort(Comparator.naturalOrder()); // ascending
names.sort(Comparator.reverseOrder()); // descending
names.sort(Comparator.comparingInt(String::length)); // by length

// Chained comparator: sort by length descending, then alphabetically
names.sort(Comparator.comparingInt(String::length)
.reversed()
.thenComparing(Comparator.naturalOrder()));

// Map utility methods (Java 8+)
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 85);

scores.getOrDefault("Carol", 0); // 0 if Carol is absent
scores.putIfAbsent("Alice", 100); // ignored because Alice exists
scores.computeIfAbsent("Dave", k -> 75); // adds Dave with score 75
scores.merge("Alice", 5, Integer::sum); // Alice's score += 5
scores.forEach((name, score) ->
System.out.println(name + ": " + score));

Pro Tips

Immutable collections vs defensive copying:

  • List.of(), Map.of() etc. (Java 9+ factory methods): truly immutable— throws exception on modification
  • Collections.unmodifiableList(): just a wrapper — if the underlying collection changes, the view changes too
List<String> original = new ArrayList<>(List.of("A", "B"));
List<String> unmod = Collections.unmodifiableList(original);

original.add("C"); // modify the original
System.out.println(unmod); // [A, B, C] -- the view changed too!

// Truly immutable copy
List<String> trulyImmutable = List.copyOf(original); // Java 10+

When returning a collection from a method, return Collections.emptyList() instead of null. This prevents NullPointerExceptions and keeps the calling code clean.