Skip to content
intermediatePhase 13 · Java Collections

Collections Utility Class

Use Collections.sort(), reverse(), shuffle(), and other utility methods.

30m
2 problems
Topic Progress0%

Sorting

Sorting with Collections

The Collections class provides static methods for sorting, reversing, and shuffling lists.

import java.util.*;

public class SortingDemo {
    public static void main(String[] args) {
        // Sort - natural ordering
        List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));
        Collections.sort(numbers);
        System.out.println("Sorted: " + numbers); // [1, 2, 3, 5, 8, 9]

        // Sort - custom comparator
        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "Alice", "Bob"));
        Collections.sort(names); // natural alphabetical
        System.out.println("Alphabetical: " + names); // [Alice, Bob, Charlie]

        Collections.sort(names, Comparator.reverseOrder());
        System.out.println("Reverse alpha: " + names); // [Charlie, Bob, Alice]

        // Sort by string length
        Collections.sort(names, Comparator.comparingInt(String::length));
        System.out.println("By length: " + names); // [Bob, Alice, Charlie]

        // Reverse
        List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Collections.reverse(list);
        System.out.println("Reversed: " + list); // [5, 4, 3, 2, 1]

        // Shuffle
        List<Integer> shuffled = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Collections.shuffle(shuffled);
        System.out.println("Shuffled: " + shuffled); // random order

        // Rotate
        List<Integer> rotated = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Collections.rotate(rotated, 2); // rotate right by 2
        System.out.println("Rotated: " + rotated); // [4, 5, 1, 2, 3]

        // Fill - replace all elements
        List<String> filled = new ArrayList<>(Arrays.asList("a", "b", "c"));
        Collections.fill(filled, "x");
        System.out.println("Filled: " + filled); // [x, x, x]

        // Swap
        List<Integer> swapped = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        Collections.swap(swapped, 0, 4); // swap indices 0 and 4
        System.out.println("Swapped: " + swapped); // [5, 2, 3, 4, 1]

        // Min and Max
        System.out.println("Min: " + Collections.min(numbers));
        System.out.println("Max: " + Collections.max(numbers));

        // Sort with nulls last
        List<String> withNulls = new ArrayList<>(Arrays.asList("b", null, "a", null, "c"));
        withNulls.sort(Comparator.nullsLast(Comparator.naturalOrder()));
        System.out.println("Nulls last: " + withNulls); // [a, b, c, null, null]
    }
}

Note: Collections.sort() modifies the list in place. For a new sorted list without modifying the original, use list.stream().sorted().collect(Collectors.toList()) or create a copy first.

Unmodifiable

Unmodifiable Collections

The Collections class provides wrappers that make collections immutable. Any attempt to modify throws UnsupportedOperationException.

import java.util.*;

public class UnmodifiableDemo {
    public static void main(String[] args) {
        // Unmodifiable List
        List<String> mutable = new ArrayList<>(Arrays.asList("a", "b", "c"));
        List<String> unmodifiable = Collections.unmodifiableList(mutable);
        System.out.println("Unmodifiable: " + unmodifiable); // [a, b, c]

        // Cannot modify
        try {
            unmodifiable.add("d");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot modify: " + e.getMessage());
        }

        // BUT: modifying the original list affects the view!
        mutable.add("d");
        System.out.println("Original: " + mutable); // [a, b, c, d]
        System.out.println("View: " + unmodifiable); // [a, b, c, d]

        // Truly immutable - copy the list
        List<String> immutable = Collections.unmodifiableList(new ArrayList<>(Arrays.asList("x", "y", "z")));
        mutable.add("e"); // doesn't affect immutable
        System.out.println("Immutable: " + immutable); // [x, y, z]

        // Unmodifiable Map
        Map<String, Integer> map = new HashMap<>();
        map.put("a", 1);
        map.put("b", 2);
        Map<String, Integer> unmodMap = Collections.unmodifiableMap(map);
        System.out.println("Unmodifiable map: " + unmodMap);

        // Unmodifiable Set
        Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
        Set<Integer> unmodSet = Collections.unmodifiableSet(set);
        System.out.println("Unmodifiable set: " + unmodSet);

        // Java 9+ shortcut
        List<String> ofList = List.of("a", "b", "c"); // truly immutable
        Map<String, Integer> ofMap = Map.of("a", 1, "b", 2); // truly immutable
        System.out.println("List.of: " + ofList);
        System.out.println("Map.of: " + ofMap);
    }
}

Key distinction:

  • Collections.unmodifiableList(list) — wrapper that delegates to the original list. Changes to the original are visible through the wrapper.
  • List.of(...) (Java 9+) — truly immutable copy. No connection to any other list.

Singleton

Collections.singleton()

The singleton methods return immutable sets containing exactly one element. They are more memory-efficient than creating a full HashSet for a single element.

import java.util.*;

public class SingletonDemo {
    public static void main(String[] args) {
        // Singleton Set
        Set<String> single = Collections.singleton("Hello");
        System.out.println("Singleton set: " + single); // [Hello]
        System.out.println("Size: " + single.size()); // 1
        System.out.println("Contains: " + single.contains("Hello")); // true

        // Cannot modify
        try {
            single.add("World");
        } catch (UnsupportedOperationException e) {
            System.out.println("Cannot add: immutable");
        }

        // Singleton List
        List<Integer> singleList = Collections.singletonList(42);
        System.out.println("Singleton list: " + singleList); // [42]

        // Singleton Map
        Map<String, Integer> singleMap = Collections.singletonMap("key", 100);
        System.out.println("Singleton map: " + singleMap); // {key=100}

        // Use cases
        System.out.println("\n--- Use Cases ---");

        // 1. Method returning immutable single-element collection
        Set<String> getPermissions() {
            return Collections.singleton("READ");
        }

        // 2. As argument to methods expecting Collection
        List<String> list = new ArrayList<>(Collections.singleton("default"));
        System.out.println("From singleton: " + list); // [default]

        // 3. Default value pattern
        String input = null;
        Set<String> values = input != null ?
            Set.of(input) : Collections.singleton("default");
        System.out.println("Default: " + values); // [default]

        // Java 9+ alternative
        Set<String> java9 = Set.of("Hello"); // also immutable, one element
        System.out.println("Java 9 Set.of: " + java9);
    }

    // Method returning singleton set
    static Set<String> getPermissions() {
        return Collections.singleton("READ");
    }
}

When to use singleton:

  • Returning a single-element immutable collection from a method
  • As a default value when no data is available
  • When you need a Collection type but only have one element
  • Memory-efficient alternative to new HashSet<>(Arrays.asList(e))

Utility Methods

Other Utility Methods

The Collections class provides many other useful utility methods.

import java.util.*;

public class UtilityMethodsDemo {
    public static void main(String[] args) {
        // Frequency - count occurrences
        List<String> list = Arrays.asList("a", "b", "a", "c", "a", "b");
        System.out.println("Frequency of a: " + Collections.frequency(list, "a")); // 3
        System.out.println("Frequency of b: " + Collections.frequency(list, "b")); // 2
        System.out.println("Frequency of d: " + Collections.frequency(list, "d")); // 0

        // Disjoint - check if two collections have no common elements
        Set<Integer> setA = new HashSet<>(Arrays.asList(1, 2, 3));
        Set<Integer> setB = new HashSet<>(Arrays.asList(4, 5, 6));
        System.out.println("Disjoint: " + Collections.disjoint(setA, setB)); // true

        setB.add(3);
        System.out.println("Disjoint: " + Collections.disjoint(setA, setB)); // false

        // indexOfSubList - find sublist position
        List<Integer> main = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> sub = Arrays.asList(3, 4);
        System.out.println("indexOfSubList: " + Collections.indexOfSubList(main, sub)); // 2

        // lastIndexOfSubList
        System.out.println("lastIndexOfSubList: " + Collections.lastIndexOfSubList(main, sub)); // 2

        // List.nCopies - create list with n copies of same element
        List<String> copies = Collections.nCopies(5, "hello");
        System.out.println("nCopies: " + copies); // [hello, hello, hello, hello, hello]

        // Enumeration (legacy - for backward compatibility)
        List<String> legacy = Arrays.asList("a", "b", "c");
        Enumeration<String> enumList = Collections.enumeration(legacy);
        while (enumList.hasMoreElements()) {
            System.out.print(enumList.nextElement() + " ");
        }
        System.out.println();

        // List from Enumeration
        List<String> fromEnum = Collections.list(Collections.enumeration(legacy));
        System.out.println("From enumeration: " + fromEnum);

        // synchronized wrappers
        List<String> syncList = Collections.synchronizedList(new ArrayList<>());
        Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());
        Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
        System.out.println("Created synchronized collections");
    }
}

Summary of key methods:

  • frequency(collection, obj) — count occurrences
  • disjoint(col1, col2) — check if no common elements
  • nCopies(n, obj) — create list with n copies
  • indexOfSubList(list, sub) — find sublist position
  • synchronizedList/Map/Set — thread-safe wrappers

Practice Problems

0/2solved
Sort and Remove Duplicates

Write a method that takes a List of Integers, removes duplicates, sorts them in ascending order, and returns the result as a new List. Use Collections utility methods.

Solution
import java.util.*;

public class SortAndDeduplicate {
    public static List<Integer> sortAndRemoveDuplicates(List<Integer> list) {
        List<Integer> result = new ArrayList<>(new TreeSet<>(list));
        return result;
    }
}
Create Unmodifiable Copy

Write a method that takes a Map and returns a truly unmodifiable copy. The original map should be modifiable without affecting the returned map.

Solution
import java.util.*;

public class ImmutableMapCopy {
    public static <K, V> Map<K, V> unmodifiableCopy(Map<K, V> original) {
        return Collections.unmodifiableMap(new HashMap<>(original));
    }
}

Quiz

1. What does Collections.unmodifiableList() return?

Question 1 options

2. What is the purpose of Collections.singleton()?

Question 2 options

3. How do you count occurrences of an element in a list?

Question 3 options

4. What is the primary purpose of Collections Utility Class?

Question 4 options

Flashcards

Question

What does Collections.sort() do?

Answer

Sorts the list in-place according to natural ordering or a custom Comparator. Time complexity is O(n log n). Modifies the original list.

Question

What is the difference between Collections.unmodifiableList() and List.of()?

Answer

unmodifiableList() is a wrapper that delegates to the original list. List.of() creates a truly immutable copy. Changes to the original are visible through unmodifiableList but not List.of.

Question

How do you create a thread-safe collection using Collections utility?

Answer

Use Collections.synchronizedList(), synchronizedMap(), or synchronizedSet(). These wrap the collection with synchronized access. For concurrent access, consider java.util.concurrent classes instead.

Question

What is Collections Utility Class?

Answer

Collections Utility Class is a key concept in Java programming.

Question

When to use Collections Utility Class?

Answer

Use Collections Utility Class when building production systems that require reliability, scalability, and maintainability.

Revision Notes

Key Takeaways

  • 1.Collections.sort() modifies the list in-place
  • 2.unmodifiableList() is a wrapper — changes to original are visible
  • 3.singleton() is memory-efficient for single-element immutable collections
  • 4.frequency() counts occurrences of an element in a collection

Interview Tips

  • Know that unmodifiableList is a wrapper, not a copy
  • Understand when to use List.of() vs Collections.unmodifiableList()
  • Be aware of Collections.sort() modifying the original list
  • Know the utility methods: frequency, disjoint, nCopies

Cheat Sheet

Collections Utility Cheat Sheet

Sorting & Ordering

  • sort(list) → O(n log n), in-place
  • reverse(list) → reverse in-place
  • shuffle(list) → random order
  • rotate(list, dist) → rotate elements
  • swap(list, i, j) → swap two elements

Unmodifiable

  • unmodifiableList/Map/Set → wrapper view
  • Changes to original visible through wrapper!
  • For true immutability: new ArrayList<>(list)

Singleton

  • singleton(e) → immutable set with one element
  • singletonList(e) → immutable list with one element
  • singletonMap(k, v) → immutable map with one entry

Utility

  • frequency(collection, obj) → count occurrences
  • disjoint(col1, col2) → no common elements
  • nCopies(n, obj) → list with n copies