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
Collectiontype 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 occurrencesdisjoint(col1, col2)— check if no common elementsnCopies(n, obj)— create list with n copiesindexOfSubList(list, sub)— find sublist positionsynchronizedList/Map/Set— thread-safe wrappers
Practice Problems
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;
}
}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?
2. What is the purpose of Collections.singleton()?
3. How do you count occurrences of an element in a list?
4. What is the primary purpose of Collections Utility Class?
Flashcards
Question
What does Collections.sort() do?
Click to reveal answer
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()?
Click to reveal answer
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?
Click to reveal answer
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?
Click to reveal answer
Answer
Collections Utility Class is a key concept in Java programming.
Question
When to use Collections Utility Class?
Click to reveal answer
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