Skip to content
Java collections 7 min read

Collections Utility Class

The Collections class (note the s — not to be confused with the Collection interface) is a treasure chest of static utility methods that operate on lists, sets, and maps. Think of it as the Swiss Army knife that comes free with every Java installation.

What Is the Collections Class?

java.util.Collections is a final class with a private constructor — you can never instantiate it. Every method is static, so you call them directly on the class:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class QuickDemo {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>(List.of(5, 2, 8, 1, 9, 3));
        Collections.sort(numbers);
        System.out.println(numbers);
    }
}

Output:

[1, 2, 3, 5, 8, 9]

Note: Collections works on any class that implements Collection or List. Most methods accept a List<T> or Collection<T> parameter, not a raw array. For array utilities, see the Arrays class.


Sorting

sort()

List<String> names = new ArrayList<>(List.of("Zara", "Alice", "Mike", "Bob"));
Collections.sort(names);                    // natural (alphabetical) order
System.out.println(names);

Collections.sort(names, Comparator.reverseOrder()); // reverse order
System.out.println(names);

Output:

[Alice, Bob, Mike, Zara]
[Zara, Mike, Bob, Alice]

You can supply your own Comparator as the second argument to sort by any custom rule — for example, by string length:

Collections.sort(names, Comparator.comparingInt(String::length));

reverseOrder()

Collections.reverseOrder() returns a Comparator that imposes the reverse of natural ordering. It’s handy when sorting in descending order without writing a lambda:

List<Integer> scores = new ArrayList<>(List.of(88, 72, 95, 60));
Collections.sort(scores, Collections.reverseOrder());
System.out.println(scores); // [95, 88, 72, 60]

Searching

binarySearch()

binarySearch() finds an element in a sorted list using the binary search algorithm, returning the index if found or a negative value if not.

List<Integer> sorted = new ArrayList<>(List.of(10, 20, 30, 40, 50));
int idx = Collections.binarySearch(sorted, 30);
System.out.println("Found at index: " + idx); // Found at index: 2

Warning: The list must be sorted before calling binarySearch(). Calling it on an unsorted list produces undefined results.


Shuffling and Reversing

shuffle()

Randomly rearranges the elements of a list — useful for card games, quiz randomization, or any scenario requiring random ordering:

List<String> deck = new ArrayList<>(List.of("Ace", "King", "Queen", "Jack", "10"));
Collections.shuffle(deck);
System.out.println(deck); // e.g. [Queen, 10, Ace, Jack, King]

You can optionally pass a Random instance for reproducible results:

Collections.shuffle(deck, new java.util.Random(42));

reverse()

Reverses the order of elements in-place:

List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4, 5));
Collections.reverse(nums);
System.out.println(nums); // [5, 4, 3, 2, 1]

rotate()

Shifts elements by a given distance. Positive distance rotates right; negative rotates left:

List<String> items = new ArrayList<>(List.of("A", "B", "C", "D", "E"));
Collections.rotate(items, 2);
System.out.println(items); // [D, E, A, B, C]

Min and Max

List<Integer> values = List.of(3, 1, 4, 1, 5, 9, 2, 6);
System.out.println(Collections.min(values)); // 1
System.out.println(Collections.max(values)); // 9

Both methods also accept a Comparator if your objects don’t implement Comparable or you want a custom rule:

List<String> words = List.of("apple", "fig", "banana", "kiwi");
String shortest = Collections.min(words, Comparator.comparingInt(String::length));
System.out.println(shortest); // fig

Filling and Copying

fill()

Replaces every element in a list with the specified value — handy for resetting a list:

List<String> slots = new ArrayList<>(List.of("X", "X", "X", "X"));
Collections.fill(slots, "-");
System.out.println(slots); // [-, -, -, -]

copy()

Copies all elements from a source list into a destination list. The destination must be at least as large as the source:

List<String> src  = List.of("one", "two", "three");
List<String> dest = new ArrayList<>(List.of("a", "b", "c"));
Collections.copy(dest, src);
System.out.println(dest); // [one, two, three]

Warning: Collections.copy() does not add elements; it only overwrites existing positions. If dest.size() < src.size(), you get an IndexOutOfBoundsException.

nCopies()

Returns an immutable list containing n copies of the given object:

List<String> repeated = Collections.nCopies(5, "hello");
System.out.println(repeated); // [hello, hello, hello, hello, hello]

Frequency and Disjoint

frequency()

Counts how many times an element appears in a collection:

List<String> colors = List.of("red", "blue", "red", "green", "red");
System.out.println(Collections.frequency(colors, "red")); // 3

disjoint()

Returns true if two collections have no elements in common:

List<Integer> a = List.of(1, 2, 3);
List<Integer> b = List.of(4, 5, 6);
List<Integer> c = List.of(3, 7, 8);

System.out.println(Collections.disjoint(a, b)); // true
System.out.println(Collections.disjoint(a, c)); // false

Thread-Safe Wrappers

Standard collections like ArrayList and HashMap are not thread-safe. Collections offers synchronized wrappers that add a mutex around every method:

import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

List<String> safe = Collections.synchronizedList(new ArrayList<>());
safe.add("thread-safe write");

Equivalent wrappers exist for all major collection types:

MethodWraps
synchronizedList(list)Any List
synchronizedSet(set)Any Set
synchronizedMap(map)Any Map
synchronizedSortedSet(set)Any SortedSet
synchronizedSortedMap(map)Any SortedMap

Tip: For high-concurrency code, prefer Concurrent Collections (ConcurrentHashMap, CopyOnWriteArrayList) over synchronized wrappers — they offer better throughput through fine-grained locking or lock-free algorithms.


Unmodifiable Wrappers

Sometimes you want to hand a collection to external code and guarantee it won’t be changed. Unmodifiable wrappers throw UnsupportedOperationException on any mutating call:

List<String> mutable = new ArrayList<>(List.of("a", "b", "c"));
List<String> readOnly = Collections.unmodifiableList(mutable);

System.out.println(readOnly.get(0)); // a
readOnly.add("d");                   // throws UnsupportedOperationException
MethodWraps
unmodifiableList(list)Any List
unmodifiableSet(set)Any Set
unmodifiableMap(map)Any Map
unmodifiableSortedSet(set)Any SortedSet
unmodifiableSortedMap(map)Any SortedMap

Note: Java 9+ offers List.of(), Set.of(), and Map.of() which create truly immutable collections without wrapping overhead. Prefer those for new code.


Singleton Collections

Need a collection with exactly one element? Collections has factory methods for that:

List<String>  single = Collections.singletonList("only");
Set<Integer>  oneSet = Collections.singleton(42);
Map<String,Integer> oneMap = Collections.singletonMap("key", 1);

These are immutable and extremely memory-efficient — great for passing a single argument where a collection is expected.

emptyList / emptySet / emptyMap

Similarly, typed empty collections avoid null checks and unnecessary allocations:

List<String> nothing = Collections.emptyList();

Tip: Returning Collections.emptyList() from a method instead of null eliminates the dreaded NullPointerException at the call site.


swap() and addAll()

swap()

Swaps two elements at specified indices:

List<String> letters = new ArrayList<>(List.of("A", "B", "C", "D"));
Collections.swap(letters, 0, 3);
System.out.println(letters); // [D, B, C, A]

addAll()

Adds multiple elements to a collection in one call — more concise than looping:

List<String> list = new ArrayList<>();
Collections.addAll(list, "X", "Y", "Z");
System.out.println(list); // [X, Y, Z]

Under the Hood

Why a Final Utility Class?

Collections is declared final with a private Collections() {} constructor — the classic utility class pattern. This prevents subclassing and instantiation, making it clear the class is purely a namespace for static methods. The JVM treats calls to these static methods as direct invocations without virtual dispatch overhead.

sort() and TimSort

Collections.sort() delegates to List.sort() which uses TimSort, a hybrid merge-sort / insertion-sort algorithm. TimSort is optimized for real-world data that often contains already-sorted runs. It runs in O(n log n) worst-case and O(n) best-case (already sorted). The sort is stable — equal elements preserve their original relative order, which matters when sorting objects with multiple fields.

Unmodifiable vs Immutable

Unmodifiable wrappers are views over the original collection. If someone still holds a reference to the backing list and mutates it, the “read-only” view reflects those changes. List.of() collections (Java 9+) store data in a private array with no backing mutable reference, so they are truly immutable.

Synchronized Wrappers Are Coarse-Grained

Every method on a synchronized wrapper acquires the same intrinsic lock (the wrapper object itself). This means add, get, size, and iteration all contend on one lock — fine for low-concurrency but a bottleneck under heavy parallel access. Iteration also requires external synchronization:

synchronized(safe) {
    for (String s : safe) {
        System.out.println(s);
    }
}

Forgetting this synchronized block during iteration can still cause ConcurrentModificationException.


Quick Reference

MethodWhat it does
sort(list)Natural-order sort
sort(list, cmp)Custom comparator sort
binarySearch(list, key)Binary search (list must be sorted)
reverse(list)Reverse in-place
shuffle(list)Random permutation
rotate(list, dist)Cyclic rotation
min(col) / max(col)Find min / max element
fill(list, obj)Overwrite all elements
copy(dest, src)Copy src → dest
nCopies(n, obj)Immutable list of n copies
frequency(col, obj)Count occurrences
disjoint(c1, c2)No common elements?
swap(list, i, j)Swap two positions
addAll(col, …)Bulk add varargs
synchronizedList(list)Thread-safe wrapper
unmodifiableList(list)Read-only view
singletonList(obj)Immutable one-element list
emptyList()Immutable empty list

  • Sorting Collections — practical guide to sorting with Comparator and Comparable together
  • Comparable — make your objects naturally sortable so Collections.sort() works out of the box
  • Comparator — define custom sort orders for use with Collections.sort()
  • ArrayList — the list type you’ll use most often with these utilities
  • Concurrent Collections — thread-safe alternatives to synchronized wrappers for high-throughput code
  • Arrays Utility Class — the equivalent toolkit for plain Java arrays
Last updated June 13, 2026
Was this helpful?