Collections Class

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 84 of 133

java.util.Collections (with an s) is a utility class of static methods that operate on or return collections. It provides ready-made algorithms (sorting, searching, shuffling, reversing, finding the minimum or maximum), factory methods for special collections (empty, single-element, repeated), and wrappers that make a collection unmodifiable, synchronized, or type-checked. It is distinct from Collection (no s), the root interface that List, Set, and Queue extend.

CollectionCollections
KindInterfaceFinal utility class with a private constructor
PurposeDefines what a collection isStatic helper methods that work on collections
ExampleCollection<String> c = new ArrayList<>();Collections.sort(list);

The Arrays class plays the same role for arrays.

Sorting

import java.util.*;

List<Integer> scores = new ArrayList<>(List.of(72, 95, 58, 88));

Collections.sort(scores);                                // [58, 72, 88, 95]
Collections.sort(scores, Comparator.reverseOrder());     // [95, 88, 72, 58]

Collections.sort(list) requires the elements to be Comparable; the two-argument form takes a Comparator. Both sort in place, stably. Since Java 8 they simply call list.sort(...), which is the more common style today. The list must be modifiable: sorting List.of(...) throws UnsupportedOperationException.

Searching, Minimum, Maximum, and Frequency

List<Integer> n = new ArrayList<>(List.of(5, 3, 8, 1));
Collections.sort(n);                             // [1, 3, 5, 8]

int pos = Collections.binarySearch(n, 5);        // 2 (list must be sorted)
int low = Collections.min(n);                    // 1
int high = Collections.max(n);                   // 8

List<String> words = List.of("to", "be", "or", "not", "to", "be");
int count = Collections.frequency(words, "to");  // 2

String longest = Collections.max(words, Comparator.comparingInt(String::length));   // "not"
MethodPurpose
binarySearch(list, key) / (list, key, cmp)Search a sorted list; same negative "insertion point" convention as Arrays.binarySearch
min(coll) / max(coll)Smallest / largest by natural order
min(coll, cmp) / max(coll, cmp)By a comparator
frequency(coll, o)Number of elements equal to o
disjoint(c1, c2)true if the collections share no elements
indexOfSubList(source, target)Position of a sublist, or -1

min and max work on any Collection, not just lists, and throw NoSuchElementException if it is empty.

Rearranging Lists

List<Integer> n = new ArrayList<>(List.of(1, 3, 5, 8));

Collections.reverse(n);          // [8, 5, 3, 1]
Collections.swap(n, 0, 3);       // [1, 5, 3, 8]
Collections.rotate(n, 1);        // [8, 1, 5, 3]  every element moves one place right
Collections.shuffle(n);          // random order
Collections.fill(n, 0);          // [0, 0, 0, 0]
MethodEffect
reverse(list)Reverse in place
shuffle(list) / shuffle(list, random)Random permutation; pass a seeded Random for repeatable results
swap(list, i, j)Exchange two positions
rotate(list, distance)Shift elements; the ones pushed off one end wrap to the other
fill(list, value)Replace every element
copy(dest, src)Copy src into the start of dest (dest must already be large enough)

rotate combined with subList moves a block of elements, for example Collections.rotate(list.subList(2, 6), -1) shifts the elements at indexes 2–5 one place left.

Creating Special Collections

Empty collections

List<String> none = Collections.emptyList();
Map<String, Integer> nothing = Collections.emptyMap();
Set<String> noneSet = Collections.emptySet();

These are shared, immutable singletons. Returning one instead of null lets callers loop over the result without a null check. List.of(), Set.of(), and Map.of() serve the same purpose in modern code.

Single-element and repeated collections

Set<String> admins = Collections.singleton("root");               // immutable set of one
List<String> one = Collections.singletonList("only");
Map<String, Integer> pair = Collections.singletonMap("timeout", 30);

List<String> dashes = Collections.nCopies(5, "-");                // [-, -, -, -, -]
String rule = String.join("", Collections.nCopies(20, "="));      // "===================="

nCopies returns an immutable list that stores the element once, so even nCopies(1_000_000, x) uses almost no memory. Wrapping it in new ArrayList<>(...) gives a modifiable list pre-filled with a value.

Adding several elements

List<String> langs = new ArrayList<>();
Collections.addAll(langs, "Java", "Bash", "C");

addAll with varargs avoids creating a temporary list.

Wrappers

Wrapper methods return a new view around an existing collection, adding a behavior without copying the data.

Unmodifiable views

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

readOnly.add("c");             // UnsupportedOperationException
internal.add("c");
System.out.println(readOnly);  // [a, b, c]: the view reflects the backing list

Variants exist for every collection type: unmodifiableSet, unmodifiableMap, unmodifiableCollection, unmodifiableSortedMap, and others. Use a view when callers should see live data but must not change it. Use List.copyOf when they should get an independent snapshot.

Synchronized wrappers

List<String> shared = Collections.synchronizedList(new ArrayList<>());

Each method call on the wrapper is guarded by a lock. Iteration is not automatically safe: you must hold the lock for the whole loop:

synchronized (shared) {
    for (String s : shared) {
        process(s);
    }
}

In modern code, purpose-built concurrent collections (ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue) are usually better choices than synchronized wrappers. They are covered in the concurrency section.

Checked wrappers

List<String> safe = Collections.checkedList(new ArrayList<>(), String.class);

A checked wrapper verifies the type of every element added, at runtime. It helps track down bugs where legacy code using raw types inserts the wrong kind of object into a generic collection: the error occurs at the point of insertion rather than later, when the element is read.

Reverse-Order Comparators

List<String> names = new ArrayList<>(List.of("Linus", "Ada", "Grace"));
names.sort(Collections.reverseOrder());                    // [Linus, Grace, Ada]
names.sort(Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));

Collections.reverseOrder() is equivalent to Comparator.reverseOrder().

Collections Versus Newer APIs

Many Collections methods now have more modern equivalents. Both styles are common in real code:

TaskCollectionsModern alternative
Sort a listCollections.sort(list)list.sort(null)
Empty immutable listCollections.emptyList()List.of()
Immutable copyCollections.unmodifiableList(new ArrayList<>(x))List.copyOf(x)
MaximumCollections.max(list)list.stream().max(...)
Reverse view(none)list.reversed() (Java 21)

The algorithms with no direct replacement, such as shuffle, rotate, swap, frequency, disjoint, and nCopies, remain the standard way to perform those operations.

Practical Example: Weighted Raffle

Students earn raffle tickets for completed lessons. The program builds the ticket list, shuffles it, draws three distinct winners, and exposes a read-only participant list.

import java.util.*;

public class Raffle {
    public static void main(String[] args) {
        List<String> entries = new ArrayList<>();
        entries.addAll(Collections.nCopies(3, "ada"));      // 3 tickets
        entries.addAll(Collections.nCopies(1, "linus"));
        entries.addAll(Collections.nCopies(2, "grace"));
        Collections.addAll(entries, "alan", "margaret");

        System.out.println("Tickets: " + entries.size());
        System.out.println("Ada's tickets: " + Collections.frequency(entries, "ada"));

        Collections.shuffle(entries, new Random(2026));
        System.out.println("Draw order: " + entries);

        Set<String> winners = new LinkedHashSet<>();
        for (String name : entries) {
            if (winners.size() == 3) break;
            winners.add(name);
        }
        System.out.println("Winners: " + winners);

        List<String> unique = new ArrayList<>(new TreeSet<>(entries));
        System.out.println("Participants: " + unique);
        System.out.println("Alphabetically last: " + Collections.max(unique));

        List<String> readOnly = Collections.unmodifiableList(unique);
        try {
            readOnly.add("hacker");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot modify the participant list");
        }
    }
}

Output:

Tickets: 8
Ada's tickets: 3
Draw order: [alan, ada, grace, linus, ada, ada, margaret, grace]
Winners: [alan, ada, grace]
Participants: [ada, alan, grace, linus, margaret]
Alphabetically last: margaret
Cannot modify the participant list

nCopies adds several tickets for the same student in one call, and addAll adds single entries without building a temporary list. frequency counts a student's tickets. shuffle with a seeded Random produces the same draw on every run, which is useful for testing or for publishing a verifiable draw; remove the seed (or use SecureRandom for anything where fairness must be guaranteed) for a truly unpredictable result. A LinkedHashSet keeps the first three distinct names in draw order, so a student with several tickets cannot win twice. Finally, unmodifiableList hands out the participant list safely.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Collections Class and get answers drawn from it.

Signed-in readers only.