Overview
The java.util.Collections class provides static methods that operate on or return collections. These utility methods include sorting, searching, shuffling, and synchronization wrappers.
Sorting Methods
sort() - Natural Ordering
import java.util.*; public class SortExamples { public static void main(String[] args) { // Sorting List with natural ordering List<String> names = new ArrayList<>(); names.add("John"); names.add("Alice"); names.add("Bob"); names.add("Diana"); System.out.println("Original: " + names); Collections.sort(names); System.out.println("Sorted (natural): " + names); // Sorting integers List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9); System.out.println("Original numbers: " + numbers); Collections.sort(numbers); System.out.println("Sorted numbers: " + numbers); // Sorting with custom comparator List<String> customSort = new ArrayList<>(names); Collections.sort(customSort, Collections.reverseOrder()); System.out.println("Reverse order: " + customSort); // Case-insensitive sorting List<String> mixedCase = Arrays.asList("apple", "Banana", "cherry", "Date"); Collections.sort(mixedCase, String.CASE_INSENSITIVE_ORDER); System.out.println("Case-insensitive sort: " + mixedCase); } } sort() with Custom Comparator
import java.util.*; class Employee { String name; int age; double salary; public Employee(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; } @Override public String toString() { return name + " (" + age + ", $" + salary + ")"; } } public class CustomSorting { public static void main(String[] args) { List<Employee> employees = Arrays.asList( new Employee("John", 30, 50000), new Employee("Alice", 25, 60000), new Employee("Bob", 35, 45000), new Employee("Diana", 28, 70000) ); // Sort by age List<Employee> byAge = new ArrayList<>(employees); Collections.sort(byAge, (e1, e2) -> e1.age - e2.age); System.out.println("Sorted by age: " + byAge); // Sort by salary (descending) List<Employee> bySalary = new ArrayList<>(employees); Collections.sort(bySalary, (e1, e2) -> Double.compare(e2.salary, e1.salary)); System.out.println("Sorted by salary (desc): " + bySalary); // Sort by name List<Employee> byName = new ArrayList<>(employees); Collections.sort(byName, (e1, e2) -> e1.name.compareTo(e2.name)); System.out.println("Sorted by name: " + byName); // Using Comparator.comparing (Java 8+) List<Employee> byAgeModern = new ArrayList<>(employees); Collections.sort(byAgeModern, Comparator.comparing(emp -> emp.age)); System.out.println("Sorted by age (modern): " + byAgeModern); } } Searching Methods
binarySearch()
import java.util.*; public class BinarySearchExamples { public static void main(String[] args) { // Binary search on sorted list List<Integer> numbers = Arrays.asList(1, 3, 5, 7, 9, 11, 13, 15); System.out.println("List: " + numbers); int index = Collections.binarySearch(numbers, 7); System.out.println("Index of 7: " + index); index = Collections.binarySearch(numbers, 8); System.out.println("Index of 8: " + index); // Negative = not found // Binary search with custom comparator List<String> names = Arrays.asList("Alice", "Bob", "Diana", "John"); Collections.sort(names); index = Collections.binarySearch(names, "Diana"); System.out.println("Index of 'Diana': " + index); // Case-insensitive binary search List<String> mixedCase = Arrays.asList("apple", "Banana", "cherry", "Date"); Collections.sort(mixedCase, String.CASE_INSENSITIVE_ORDER); index = Collections.binarySearch(mixedCase, "BANANA", String.CASE_INSENSITIVE_ORDER); System.out.println("Index of 'BANANA' (case-insensitive): " + index); // Binary search on custom objects List<Employee> employees = Arrays.asList( new Employee("John", 30, 50000), new Employee("Alice", 25, 60000), new Employee("Bob", 35, 45000) ); Collections.sort(employees, Comparator.comparing(emp -> emp.name)); Employee searchKey = new Employee("Alice", 0, 0); index = Collections.binarySearch(employees, searchKey, Comparator.comparing(emp -> emp.name)); System.out.println("Index of Alice: " + index); } } Shuffling and Reordering
shuffle()
import java.util.*; public class ShuffleExamples { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); System.out.println("Original: " + numbers); // Shuffle with default randomness Collections.shuffle(numbers); System.out.println("Shuffled: " + numbers); // Shuffle with specific Random object (for reproducible results) List<Integer> reproducible = new ArrayList<>(numbers); Random random = new Random(42); // Fixed seed Collections.shuffle(reproducible, random); System.out.println("Shuffled with seed: " + reproducible); // Multiple shuffles List<String> cards = Arrays.asList("A♠", "K♠", "Q♠", "J♠", "10♠"); System.out.println("\nCards original: " + cards); for (int i = 1; i <= 3; i++) { Collections.shuffle(cards); System.out.println("Shuffle " + i + ": " + cards); } } } reverse()
import java.util.*; public class ReverseExamples { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); System.out.println("Original: " + numbers); Collections.reverse(numbers); System.out.println("Reversed: " + numbers); // Reverse a string list List<String> words = Arrays.asList("Hello", "World", "Java", "Collections"); System.out.println("\nOriginal words: " + words); Collections.reverse(words); System.out.println("Reversed words: " + words); // Reverse and then reverse back Collections.reverse(words); System.out.println("Back to original: " + words); } } rotate()
import java.util.*; public class RotateExamples { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); System.out.println("Original: " + numbers); // Rotate right by 2 positions Collections.rotate(numbers, 2); System.out.println("Rotated right by 2: " + numbers); // Rotate left by 3 positions (negative distance) Collections.rotate(numbers, -3); System.out.println("Rotated left by 3: " + numbers); // Practical example - rotating a task list List<String> tasks = Arrays.asList("Task1", "Task2", "Task3", "Task4", "Task5"); System.out.println("\nTask list: " + tasks); // Move completed task to end Collections.rotate(tasks, -1); System.out.println("After completing first task: " + tasks); } } swap()
import java.util.*; public class SwapExamples { public static void main(String[] args) { List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "Diana"); System.out.println("Original: " + names); // Swap elements at positions 1 and 3 Collections.swap(names, 1, 3); System.out.println("After swapping 1 and 3: " + names); // Multiple swaps List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); System.out.println("\nNumbers: " + numbers); Collections.swap(numbers, 0, numbers.size() - 1); // Swap first and last System.out.println("After swapping first and last: " + numbers); // Bubble sort style swapping (educational) if (numbers.get(0) > numbers.get(1)) { Collections.swap(numbers, 0, 1); } System.out.println("After conditional swap: " + numbers); } } Frequency and Statistics
frequency()
import java.util.*; public class FrequencyExamples { public static void main(String[] args) { List<String> words = Arrays.asList("apple", "banana", "apple", "cherry", "banana", "apple", "date"); System.out.println("Word list: " + words); int appleCount = Collections.frequency(words, "apple"); int bananaCount = Collections.frequency(words, "banana"); int orangeCount = Collections.frequency(words, "orange"); System.out.println("Frequency of 'apple': " + appleCount); System.out.println("Frequency of 'banana': " + bananaCount); System.out.println("Frequency of 'orange': " + orangeCount); // Using with custom objects List<Employee> employees = Arrays.asList( new Employee("John", 30, 50000), new Employee("Alice", 25, 60000), new Employee("John", 35, 45000), new Employee("Alice", 28, 70000) ); Employee searchEmployee = new Employee("John", 0, 0); int johnCount = Collections.frequency(employees, searchEmployee); System.out.println("\nFrequency of John: " + johnCount); // 0 - needs equals/hashCode // Better approach for custom objects long aliceCount = employees.stream() .filter(emp -> "Alice".equals(emp.name)) .count(); System.out.println("Count of Alice: " + aliceCount); } } min() and max()
import java.util.*; public class MinMaxExamples { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3, 7); System.out.println("Numbers: " + numbers); Integer min = Collections.min(numbers); Integer max = Collections.max(numbers); System.out.println("Min: " + min); System.out.println("Max: " + max); // With custom comparator List<String> words = Arrays.asList("apple", "Banana", "cherry", "Date"); String minNatural = Collections.min(words); String minCaseInsensitive = Collections.min(words, String.CASE_INSENSITIVE_ORDER); System.out.println("\nWords: " + words); System.out.println("Min (natural): " + minNatural); System.out.println("Min (case-insensitive): " + minCaseInsensitive); // With custom objects List<Employee> employees = Arrays.asList( new Employee("John", 30, 50000), new Employee("Alice", 25, 60000), new Employee("Bob", 35, 45000) ); Employee youngest = Collections.min(employees, Comparator.comparing(emp -> emp.age)); Employee highestPaid = Collections.max(employees, Comparator.comparing(emp -> emp.salary)); System.out.println("\nYoungest employee: " + youngest); System.out.println("Highest paid employee: " + highestPaid); } } Synchronization Wrappers
Synchronized Collections
import java.util.*; public class SynchronizedCollections { public static void main(String[] args) throws InterruptedException { // Create synchronized wrappers List<String> syncList = Collections.synchronizedList(new ArrayList<>()); Set<Integer> syncSet = Collections.synchronizedSet(new HashSet<>()); Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>()); // Thread-safe operations Runnable listWriter = () -> { for (int i = 0; i < 1000; i++) { syncList.add("Item-" + i); } }; Runnable setWriter = () -> { for (int i = 0; i < 1000; i++) { syncSet.add(i); } }; // Start multiple threads Thread t1 = new Thread(listWriter); Thread t2 = new Thread(listWriter); Thread t3 = new Thread(setWriter); Thread t4 = new Thread(setWriter); t1.start(); t2.start(); t3.start(); t4.start(); t1.join(); t2.join(); t3.join(); t4.join(); System.out.println("SyncList size: " + syncList.size()); System.out.println("SyncSet size: " + syncSet.size()); // Important: When iterating, you must synchronize manually synchronized(syncList) { Iterator<String> it = syncList.iterator(); while (it.hasNext()) { // Safe iteration String item = it.next(); } } } } Unmodifiable Collections
import java.util.*; public class UnmodifiableCollections { public static void main(String[] args) { List<String> originalList = new ArrayList<>(Arrays.asList("A", "B", "C")); Set<Integer> originalSet = new HashSet<>(Arrays.asList(1, 2, 3)); Map<String, Integer> originalMap = new HashMap<>(); originalMap.put("One", 1); originalMap.put("Two", 2); // Create unmodifiable views List<String> unmodifiableList = Collections.unmodifiableList(originalList); Set<Integer> unmodifiableSet = Collections.unmodifiableSet(originalSet); Map<String, Integer> unmodifiableMap = Collections.unmodifiableMap(originalMap); System.out.println("Unmodifiable list: " + unmodifiableList); System.out.println("Unmodifiable set: " + unmodifiableSet); System.out.println("Unmodifiable map: " + unmodifiableMap); // These operations will throw UnsupportedOperationException try { unmodifiableList.add("D"); // Throws exception } catch (UnsupportedOperationException e) { System.out.println("Cannot modify unmodifiable list"); } try { unmodifiableSet.remove(1); // Throws exception } catch (UnsupportedOperationException e) { System.out.println("Cannot modify unmodifiable set"); } // But original collections can still be modified originalList.add("D"); originalSet.add(4); originalMap.put("Three", 3); System.out.println("After modifying originals:"); System.out.println("Unmodifiable list: " + unmodifiableList); System.out.println("Unmodifiable set: " + unmodifiableSet); System.out.println("Unmodifiable map: " + unmodifiableMap); } } Fill and Copy Operations
fill()
import java.util.*; public class FillExamples { public static void main(String[] args) { // Fill a list with same value List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D", "E")); System.out.println("Original: " + list); Collections.fill(list, "X"); System.out.println("After fill with 'X': " + list); // Fill an array Integer[] numbers = new Integer[5]; Arrays.fill(numbers, 42); System.out.println("Filled array: " + Arrays.toString(numbers)); // Practical example - resetting values List<Boolean> flags = new ArrayList<>(Collections.nCopies(10, false)); System.out.println("Initial flags: " + flags); Collections.fill(flags, true); System.out.println("All flags true: " + flags); } } copy()
import java.util.*; public class CopyExamples { public static void main(String[] args) { // Copy from source to destination List<String> source = Arrays.asList("A", "B", "C", "D", "E"); List<String> dest = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5")); System.out.println("Source: " + source); System.out.println("Destination before copy: " + dest); Collections.copy(dest, source); System.out.println("Destination after copy: " + dest); // What happens with different sizes List<String> smallDest = new ArrayList<>(Arrays.asList("1", "2", "3")); try { Collections.copy(smallDest, source); // Throws IndexOutOfBoundsException } catch (IndexOutOfBoundsException e) { System.out.println("Cannot copy - destination too small"); } List<String> largeDest = new ArrayList<>(Arrays.asList("1", "2", "3", "4", "5", "6", "7")); System.out.println("\nLarge destination before: " + largeDest); Collections.copy(largeDest, source); System.out.println("Large destination after: " + largeDest); } } nCopies() and singleton Methods
nCopies()
import java.util.*; public class NCopiesExamples { public static void main(String[] args) { // Create immutable list with n copies List<String> copies = Collections.nCopies(5, "Hello"); System.out.println("nCopies result: " + copies); // The list is immutable try { copies.add("World"); // Throws UnsupportedOperationException } catch (UnsupportedOperationException e) { System.out.println("nCopies list is immutable"); } // Practical uses List<String> initialList = new ArrayList<>(Collections.nCopies(10, "")); System.out.println("Initialized list: " + initialList); // Initialize with default values List<Integer> defaultNumbers = new ArrayList<>(Collections.nCopies(8, 0)); System.out.println("Default numbers: " + defaultNumbers); } } singleton Methods
import java.util.*; public class SingletonExamples { public static void main(String[] args) { // Create singleton collections Set<String> singletonSet = Collections.singleton("Unique"); List<Integer> singletonList = Collections.singletonList(42); Map<String, String> singletonMap = Collections.singletonMap("key", "value"); System.out.println("Singleton set: " + singletonSet); System.out.println("Singleton list: " + singletonList); System.out.println("Singleton map: " + singletonMap); // All are immutable try { singletonSet.add("Another"); // Throws exception } catch (UnsupportedOperationException e) { System.out.println("Singleton collections are immutable"); } // Practical use - removing single element List<String> names = new ArrayList<>(Arrays.asList("John", "Alice", "Bob", "Alice")); System.out.println("Before remove: " + names); names.removeAll(Collections.singleton("Alice")); System.out.println("After removing all 'Alice': " + names); } } Checked Collections (Type Safety)
checkedCollection(), checkedList(), checkedSet(), checkedMap()
import java.util.*; public class CheckedCollections { public static void main(String[] args) { // Create type-safe collections List<String> safeList = Collections.checkedList(new ArrayList<>(), String.class); Set<Integer> safeSet = Collections.checkedSet(new HashSet<>(), Integer.class); Map<String, Integer> safeMap = Collections.checkedMap(new HashMap<>(), String.class, Integer.class); // These work fine safeList.add("Hello"); safeSet.add(42); safeMap.put("Count", 100); System.out.println("Safe collections: " + safeList + ", " + safeSet + ", " + safeMap); // This would throw ClassCastException at the point of insertion try { // safeList.add(42); // Compile error if types are known } catch (Exception e) { System.out.println("Type violation caught: " + e); } // More realistic example with raw types List rawList = new ArrayList(); List<String> checkedList = Collections.checkedList(rawList, String.class); rawList.add("Valid"); // OK try { rawList.add(42); // Throws ClassCastException immediately } catch (ClassCastException e) { System.out.println("Caught type violation: " + e.getMessage()); } } } Empty Collections
emptyList(), emptySet(), emptyMap()
import java.util.*; public class EmptyCollections { public static void main(String[] args) { // Get immutable empty collections List<String> emptyList = Collections.emptyList(); Set<Integer> emptySet = Collections.emptySet(); Map<String, Object> emptyMap = Collections.emptyMap(); System.out.println("Empty list: " + emptyList); System.out.println("Empty set: " + emptySet); System.out.println("Empty map: " + emptyMap); // All are immutable try { emptyList.add("Something"); // Throws exception } catch (UnsupportedOperationException e) { System.out.println("Empty collections are immutable"); } // Practical use - return empty collections instead of null List<String> searchResults = searchDatabase("query"); System.out.println("Search results: " + searchResults); } // Good practice: return empty collection instead of null public static List<String> searchDatabase(String query) { if (query == null || query.trim().isEmpty()) { return Collections.emptyList(); // Better than returning null } // Actual search logic return Arrays.asList("Result1", "Result2"); } } Disjoint and AddAll
disjoint()
import java.util.*; public class DisjointExamples { public static void main(String[] args) { List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5); List<Integer> list2 = Arrays.asList(6, 7, 8, 9, 10); List<Integer> list3 = Arrays.asList(5, 6, 7, 8, 9); System.out.println("List1: " + list1); System.out.println("List2: " + list2); System.out.println("List3: " + list3); boolean disjoint1 = Collections.disjoint(list1, list2); boolean disjoint2 = Collections.disjoint(list1, list3); System.out.println("List1 and List2 are disjoint: " + disjoint1); System.out.println("List1 and List3 are disjoint: " + disjoint2); // Practical use - checking for common elements List<String> userRoles = Arrays.asList("admin", "user", "editor"); List<String> requiredRoles = Arrays.asList("admin", "superuser"); if (!Collections.disjoint(userRoles, requiredRoles)) { System.out.println("User has at least one required role"); } else { System.out.println("User has none of the required roles"); } } } addAll()
import java.util.*; public class AddAllExamples { public static void main(String[] args) { List<String> list = new ArrayList<>(); // Add multiple elements at once boolean changed = Collections.addAll(list, "A", "B", "C", "D", "E"); System.out.println("Collection changed: " + changed); System.out.println("List after addAll: " + list); // Add from array String[] moreElements = {"F", "G", "H"}; Collections.addAll(list, moreElements); System.out.println("After adding array: " + list); // Compared to List.addAll() List<String> anotherList = new ArrayList<>(); anotherList.addAll(Arrays.asList("X", "Y", "Z")); System.out.println("Using List.addAll(): " + anotherList); // Collections.addAll is more flexible Set<Integer> numberSet = new HashSet<>(); Collections.addAll(numberSet, 1, 2, 3, 2, 1); // Duplicates will be removed System.out.println("Number set: " + numberSet); } } Replacement Operations
replaceAll()
import java.util.*; public class ReplaceAllExamples { public static void main(String[] args) { List<String> words = new ArrayList<>( Arrays.asList("apple", "banana", "cherry", "apple", "date") ); System.out.println("Original: " + words); // Replace all occurrences boolean replaced = Collections.replaceAll(words, "apple", "orange"); System.out.println("Replacements made: " + replaced); System.out.println("After replaceAll: " + words); // No replacements if oldValue not found replaced = Collections.replaceAll(words, "grape", "pear"); System.out.println("Replacements made: " + replaced); System.out.println("After trying to replace grape: " + words); // Case-sensitive replacement List<String> mixedCase = Arrays.asList("Apple", "apple", "APPLE", "banana"); System.out.println("\nMixed case: " + mixedCase); Collections.replaceAll(mixedCase, "apple", "orange"); System.out.println("After case-sensitive replace: " + mixedCase); } } Performance Tips and Best Practices
import java.util.*; public class CollectionsBestPractices { public static void main(String[] args) { // 1. Use appropriate collections List<String> arrayList = new ArrayList<>(); // Random access List<String> linkedList = new LinkedList<>(); // Frequent insertions/deletions // 2. Prefer interface types List<Integer> numbers = new ArrayList<>(); Set<String> uniqueNames = new HashSet<>(); Map<String, Integer> wordCount = new HashMap<>(); // 3. Use utility methods for common operations List<String> list = Arrays.asList("A", "B", "C"); Collections.sort(list); Collections.reverse(list); Collections.shuffle(list); // 4. Use unmodifiable collections for constants final List<String> CONSTANTS = Collections.unmodifiableList( Arrays.asList("CONST1", "CONST2", "CONST3") ); // 5. Use empty collections instead of null public List<String> getResults() { return results.isEmpty() ? Collections.emptyList() : new ArrayList<>(results); } // 6. Use synchronized wrappers for thread safety List<String> threadSafeList = Collections.synchronizedList(new ArrayList<>()); // 7. Use checked collections for runtime type safety List<String> typeSafeList = Collections.checkedList(new ArrayList<>(), String.class); // 8. Use singleton collections for single elements set.removeAll(Collections.singleton("remove-me")); } } The Collections utility class is one of the most powerful and frequently used classes in Java, providing essential algorithms and wrappers that make working with collections much easier and safer.