Collections Utility Methods in Java – Complete Guide

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.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper