Sorting and Searching Collections Using Collections Utilities in Java
Course: Core Java Training
Topic: Sorting and Searching Collections Using Collections Utilities
Course Link: Core Java Training Course
Demo Link: Register for a Free Course Demo
JustAcademy Website: Visit JustAcademy
1. Introduction to Sorting and Searching Collections
Java Collections Framework provides classes and interfaces to store, organize, and manipulate groups of objects. While working with collections, developers frequently need to arrange elements in a particular order or find specific elements efficiently.
The java.util.Collections class provides several static utility methods for working with collections. Two important operations are sorting and searching. Sorting arranges elements according to a defined order, while searching helps locate an element or determine whether it exists.
For example, an application may sort student names alphabetically, arrange employee salaries from highest to lowest, or search for a product price in a sorted list.
Learning Objectives
- Understand the purpose of the
Collections utility class.
- Learn how to sort lists using natural ordering.
- Sort collections using custom comparators.
- Understand ascending and descending order.
- Search sorted lists using
Collections.binarySearch().
- Use utility methods such as
min(), max(), reverse(), and shuffle().
- Recognize common errors and follow best practices.
2. Understanding the Collections Utility Class
The Collections class belongs to the java.util package. It contains static methods that operate on collections, especially lists, and provides algorithms for sorting, searching, reversing, shuffling, and finding minimum or maximum values.
Import the class using:
import java.util.Collections;
To work with lists, you will commonly also need:
import java.util.ArrayList;
import java.util.List;
Common Collections Utility Methods
| Method |
Purpose |
Collections.sort(list) |
Sorts elements using their natural ordering. |
Collections.sort(list, comparator) |
Sorts elements according to a custom comparator. |
Collections.binarySearch(list, key) |
Searches a list using binary search. |
Collections.reverse(list) |
Reverses the current order of list elements. |
Collections.shuffle(list) |
Randomly rearranges list elements. |
Collections.min(collection) |
Finds the smallest element under natural ordering. |
Collections.max(collection) |
Finds the largest element under natural ordering. |
Collections.frequency(collection, value) |
Counts occurrences of a specified value. |
Collections.swap(list, i, j) |
Swaps elements at two indexes. |
3. Understanding Natural Ordering
Natural ordering is the default order defined by a type's Comparable implementation. For common Java types, integers are ordered numerically and strings are ordered lexicographically, based on their character values.
Examples of natural ordering:
- Numbers:
10, 20, 30, 40
- Strings:
"Apple", "Banana", "Mango"
- Characters: generally ordered by their character values.
When sorting objects using natural ordering, the elements must be mutually comparable. For custom classes, implement Comparable or provide a Comparator.
4. Sorting a List in Ascending Order
The Collections.sort(list) method arranges elements in ascending natural order. The list must support the modifications required by the sorting operation.
Example: Sorting Integers
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AscendingSortExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(50);
numbers.add(10);
numbers.add(40);
numbers.add(20);
numbers.add(30);
System.out.println("Before sorting: " + numbers);
Collections.sort(numbers);
System.out.println("After sorting: " + numbers);
}
}
Output:
Before sorting: [50, 10, 40, 20, 30]
After sorting: [10, 20, 30, 40, 50]
Explanation
- An
ArrayList stores the integer values.
- The values are initially stored in insertion order.
Collections.sort(numbers) sorts the list in ascending natural order.
- The same list contains the sorted values after the method completes.
Important: Sorting changes the list itself; it does not automatically create a separate sorted copy.
5. Sorting Strings Alphabetically
Strings can also be sorted using their natural ordering. This is useful when displaying names, product labels, city names, or other text values alphabetically according to Java's string comparison rules.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StringSortExample {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Rahul");
names.add("Amit");
names.add("Priya");
names.add("Neha");
Collections.sort(names);
System.out.println(names);
}
}
Output:
[Amit, Neha, Priya, Rahul]
Java's natural string ordering is case-sensitive and is based on character values. If an application needs case-insensitive ordering or locale-specific alphabetical rules, use an appropriate comparator or locale-aware collation utility.
6. Sorting in Descending Order
Descending order arranges elements from largest to smallest or from later to earlier according to the chosen ordering. For naturally comparable values, Collections.reverseOrder() provides a comparator that reverses natural ordering.
Example: Descending Number Sort
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class DescendingSortExample {
public static void main(String[] args) {
List<Integer> numbers =
new ArrayList<>(List.of(10, 50, 20, 40, 30));
Collections.sort(numbers, Collections.reverseOrder());
System.out.println(numbers);
}
}
Output:
[50, 40, 30, 20, 10]
Note: List.of() creates an unmodifiable list, so the example wraps it in an ArrayList before sorting.
7. Sorting Using a Custom Comparator
Sometimes natural ordering does not match the application's requirements. For example, an employee list may need to be sorted by salary, age, name, or joining date. A Comparator defines a custom comparison rule.
The Collections.sort(list, comparator) method sorts a list according to the provided comparator.
Example: Sorting Strings by Length
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CustomComparatorExample {
public static void main(String[] args) {
List<String> words =
new ArrayList<>(List.of("Java", "Collections", "API", "Code"));
Comparator<String> byLength =
Comparator.comparingInt(String::length);
Collections.sort(words, byLength);
System.out.println(words);
}
}
Output:
[API, Java, Code, Collections]
The comparator compares strings by length. Strings with equal lengths may appear in their original relative order because the sorting operation is stable. If a specific order is required for equal-length words, add a secondary comparison:
Comparator<String> byLengthThenName =
Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder());
8. Sorting Custom Objects
In real-world applications, collections often contain objects rather than simple values. Consider an application that stores employee records. Each employee has an ID, a name, and a salary. To sort these objects, you can define a comparator for the required field.
Example: Sorting Employees by Salary
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
class Employee {
private final int id;
private final String name;
private final double salary;
Employee(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
@Override
public String toString() {
return id + " " + name + " " + salary;
}
}
public class EmployeeSortExample {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee(1, "Amit", 45000));
employees.add(new Employee(2, "Priya", 60000));
employees.add(new Employee(3, "Rahul", 50000));
Collections.sort(
employees,
Comparator.comparingDouble(Employee::getSalary)
);
employees.forEach(System.out::println);
}
}
Output:
1 Amit 45000.0
3 Rahul 50000.0
2 Priya 60000.0
To sort salaries from highest to lowest, use:
employees.sort(
Comparator.comparingDouble(Employee::getSalary).reversed()
);
9. Using List.sort() as an Alternative
Modern Java also provides the List.sort() method. It accepts a comparator and can be used instead of Collections.sort() when sorting a list.
List<Integer> numbers =
new ArrayList<>(List.of(40, 10, 30, 20));
numbers.sort(null); // Natural ordering
System.out.println(numbers);
numbers.sort(Collections.reverseOrder());
System.out.println(numbers);
Output:
[10, 20, 30, 40]
[40, 30, 20, 10]
Use either approach according to project conventions and readability. Both approaches sort the list in place.
10. Searching Collections Using Binary Search
Searching means locating an element in a collection. Java provides several ways to search, including sequential searching with loops or contains() and binary searching with Collections.binarySearch().
Binary search repeatedly divides a sorted search range into smaller parts. It compares the target with the middle element and continues searching in the appropriate half.
How Binary Search Works
- Start with a list sorted in ascending order according to the intended ordering.
- Find the middle element of the current search range.
- Compare the middle element with the target value.
- If they match, return the index.
- If the target is smaller, continue in the lower half; if larger, continue in the upper half.
- Repeat until the value is found or the search range becomes empty.
For a random-access list such as an ArrayList, binary search generally performs in logarithmic time, commonly described as O(log n).
11. Using Collections.binarySearch()
The Collections.binarySearch() method searches a list for a specified key. The list must already be sorted according to the same ordering used by the search method. Searching an unsorted list produces undefined results.
Example: Searching for a Number
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BinarySearchExample {
public static void main(String[] args) {
List<Integer> numbers =
new ArrayList<>(List.of(50, 10, 40, 20, 30));
Collections.sort(numbers);
int index = Collections.binarySearch(numbers, 30);
System.out.println("Sorted list: " + numbers);
System.out.println("Index of 30: " + index);
}
}
Output:
Sorted list: [10, 20, 30, 40, 50]
Index of 30: 2
Indexes start at zero, so the value 30 is located at index 2.
12. Searching for an Element That Does Not Exist
If the target is not found, Collections.binarySearch() returns a negative value. Specifically, it returns -(insertion point) - 1. The insertion point is where the key could be inserted while maintaining the list's ordering.
List<Integer> numbers =
new ArrayList<>(List.of(10, 20, 30, 40, 50));
int result = Collections.binarySearch(numbers, 35);
if (result >= 0) {
System.out.println("Found at index: " + result);
} else {
int insertionPoint = -result - 1;
System.out.println("Not found.");
System.out.println("Insertion point: " + insertionPoint);
}
Output:
Not found.
Insertion point: 3
The value 35 belongs between 30 and 40, at index 3. The negative return value itself is not a normal list index.
13. Binary Search with a Comparator
When a list is sorted using a custom comparator, search it using the same comparator. The sorting and searching orders must agree.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ReverseBinarySearchExample {
public static void main(String[] args) {
List<Integer> numbers =
new ArrayList<>(List.of(10, 50, 20, 40, 30));
Collections.sort(numbers, Collections.reverseOrder());
int index = Collections.binarySearch(
numbers, 30, Collections.reverseOrder()
);
System.out.println(numbers);
System.out.println("Index: " + index);
}
}
Output:
[50, 40, 30, 20, 10]
Index: 2
Using the natural-order search on this reverse-sorted list would violate the search method's ordering requirement.
14. Linear Search vs. Binary Search
| Feature |
Linear Search |
Binary Search |
| Approach |
Checks elements one by one. |
Repeatedly halves the search range. |
| Sorting required |
No. |
Yes, according to the same ordering. |
| Typical time complexity |
O(n) |
O(log n) for random-access lists. |
| Java examples |
Loop, contains(), or indexOf(). |
Collections.binarySearch(). |
| Best use |
Small or unsorted collections. |
Sorted lists searched repeatedly. |
15. Finding Minimum and Maximum Elements
The Collections.min() and Collections.max() methods find the smallest and largest elements under natural ordering or a supplied comparator.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MinMaxExample {
public static void main(String[] args) {
List<Integer> numbers =
Arrays.asList(25, 10, 80, 45, 60);
System.out.println("Minimum: " + Collections.min(numbers));
System.out.println("Maximum: " + Collections.max(numbers));
}
}
Output:
Minimum: 10
Maximum: 80
These methods examine the collection and typically require O(n) time. Calling them on an empty collection throws NoSuchElementException.
16. Reversing a List
The Collections.reverse() method reverses the current order of a list. It does not sort the values in descending order unless the list was already sorted in ascending order.
List<String> names =
new ArrayList<>(List.of("Amit", "Neha", "Priya"));
Collections.reverse(names);
System.out.println(names);
Output:
[Priya, Neha, Amit]
To obtain descending natural order, sort using Collections.reverseOrder(). Use Collections.reverse() when you specifically need to reverse the list's existing sequence.
17. Shuffling a List
The Collections.shuffle() method randomly permutes the elements of a list. It can be useful for quizzes, card games, randomized practice questions, or selecting an order for a simple demonstration.
List<String> questions =
new ArrayList<>(List.of("Q1", "Q2", "Q3", "Q4", "Q5"));
Collections.shuffle(questions);
System.out.println(questions);
The output order can vary each time the program runs.
For repeatable results in tests, provide a seeded random generator supported by your Java version. Do not rely on ordinary shuffling for security-sensitive randomness.
18. Counting Frequency of Elements
The Collections.frequency() method counts how many elements in a collection are equal to a specified value.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class FrequencyExample {
public static void main(String[] args) {
List<String> fruits =
Arrays.asList("Apple", "Mango", "Apple", "Banana", "Apple");
int count = Collections.frequency(fruits, "Apple");
System.out.println("Apple appears: " + count + " times");
}
}
Output:
Apple appears: 3 times
This method is useful for simple occurrence counting. For counts of many different values, a Map can be more suitable because it allows you to maintain counts as you process the data.
19. Swapping Elements in a List
The Collections.swap() method exchanges the elements at two specified indexes. The indexes must be valid for the list.
List<Integer> numbers =
new ArrayList<>(List.of(10, 20, 30, 40));
Collections.swap(numbers, 0, 3);
System.out.println(numbers);
Output:
[40, 20, 30, 10]
This method is useful in simple rearrangement tasks and algorithm demonstrations.
20. Practical Example: Sorting and Searching Student Marks
Suppose a school application stores student marks. The program needs to sort marks in ascending order, find a particular mark, and report the minimum and maximum values.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class StudentMarksManager {
public static void main(String[] args) {
List<Integer> marks =
new ArrayList<>(List.of(78, 92, 65, 88, 74, 92));
Collections.sort(marks);
System.out.println("Sorted marks: " + marks);
int target = 88;
int index = Collections.binarySearch(marks, target);
if (index >= 0) {
System.out.println(target + " found at index " + index);
} else {
System.out.println(target + " was not found");
}
System.out.println("Lowest mark: " + Collections.min(marks));
System.out.println("Highest mark: " + Collections.max(marks));
System.out.println("Count of 92: " + Collections.frequency(marks, 92));
}
}
Sample output:
Sorted marks: [65, 74, 78, 88, 92, 92]
88 found at index 3
Lowest mark: 65
Highest mark: 92
Count of 92: 2
Because the list contains duplicate marks, binary search guarantees that a matching index is returned but does not guarantee which matching duplicate will be selected.
21. Common Errors and Troubleshooting
| Problem |
Cause |
Solution |
| Binary search returns an unexpected negative value. |
The target is absent, or the list is not ordered as required. |
Sort using the correct ordering before searching and decode negative results when needed. |
ClassCastException |
Elements are not mutually comparable, or an incompatible search key is supplied. |
Use compatible element types and a suitable comparator. |
UnsupportedOperationException |
The list does not support the modifications needed for sorting or reversing. |
Copy it into a modifiable list such as new ArrayList<>(source). |
IndexOutOfBoundsException |
An invalid index was supplied to swap() or another indexed operation. |
Check that indexes are between zero and list.size() - 1. |
NoSuchElementException |
min() or max() was called on an empty collection. |
Check whether the collection is empty first. |
| Unexpected text order. |
String natural ordering is case-sensitive. |
Use a comparator such as String.CASE_INSENSITIVE_ORDER when appropriate. |
22. Best Practices for Sorting and Searching
- Always sort a list before using
Collections.binarySearch().
- Use the same comparator for sorting and searching.
- Choose natural ordering when it clearly represents the required order.
- Use a custom
Comparator for sorting objects by business-specific fields.
- Use
Collections.reverseOrder() for descending natural ordering rather than confusing sorting with reversing.
- Check for empty collections before calling
min() or max().
- Use a modifiable list when a utility method needs to change its elements.
- Remember that sorting, reversing, shuffling, and swapping modify the supplied list.
- For case-insensitive or locale-aware text ordering, choose the comparator or collation strategy that matches the application's requirements.
- For repeated searches, consider whether maintaining sorted data is worth the cost of inserting and updating elements.
- Do not assume binary search returns the first occurrence when duplicate values exist.
23. Practice Exercises
- Create a list of ten integers and sort it in ascending order.
- Sort a list of city names in descending natural order.
- Sort a list of strings by their length and use alphabetical order to break ties.
- Search for a number in a sorted list using
Collections.binarySearch().
- Search for a missing number and calculate its insertion point from the negative result.
- Create an
Employee class and sort employees by salary from highest to lowest.
- Find the minimum and maximum values in a collection of product prices.
- Reverse a list and compare the result with sorting the same list in descending order.
- Count how many times a chosen word appears in a list.
- Shuffle a list of quiz questions and display the resulting order.
24. Mini Project: Product Price Organizer
Project objective: Build a small Java program that stores product prices, sorts them, searches for a price, and displays useful statistics.
Requirements
- Create an
ArrayList<Integer> containing sample product prices.
- Display the original list of prices.
- Sort the prices in ascending order.
- Sort the prices in descending order using
Collections.reverseOrder().
- Search for a given price using binary search after sorting in the matching order.
- Display the minimum and maximum prices.
- Count how many products have the same price.
- Handle empty input before finding minimum or maximum values.
Expected Skills
After completing this project, learners should be able to combine Java lists, sorting utilities, comparators, binary search, and collection statistics in a practical program.
25. Interview Questions and Answers
Q1. What is the Collections class in Java?
Answer: Collections is a utility class in java.util that provides static methods for operations such as sorting, searching, reversing, shuffling, and finding minimum and maximum elements.
Q2. What is the difference between Collection and Collections?
Answer: Collection is an interface that represents a group of objects. Collections is a utility class that provides static methods for operating on collection objects.
Q3. How do you sort a list in Java?
Answer: Use Collections.sort(list) for natural ordering or Collections.sort(list, comparator) for custom ordering. You can also use list.sort(comparator).
Q4. How can you sort a list in descending order?
Answer: Use Collections.sort(list, Collections.reverseOrder()) for descending natural ordering of mutually comparable elements.
Q5. What is binary search?
Answer: Binary search finds a target by repeatedly dividing a sorted search range into halves. It can achieve logarithmic search time on random-access lists.
Q6. Why must a list be sorted before binary search?
Answer: Binary search relies on the ordering of the elements to decide which half to search next. Without the required ordering, the result is undefined.
Q7. What does binarySearch() return if an element is not found?
Answer: It returns -(insertion point) - 1. The insertion point is where the target could be inserted without breaking the required order.
Q8. Can binary search find duplicate elements?
Answer: It can return an index of a matching element, but it does not guarantee which matching index is returned when duplicates exist.
Q9. What is the difference between reverse() and reverseOrder()?
Answer: Collections.reverse(list) reverses the current element sequence. Collections.reverseOrder() provides a comparator for sorting in reverse natural order.
Q10. What is a Comparator?
Answer: A Comparator defines a comparison rule that can be used to sort objects according to fields or business requirements without requiring the class to define that ordering as its natural order.
Q11. What is the time complexity of binary search?
Answer: It is typically O(log n) for random-access lists such as ArrayList. For large linked lists, element traversal can make the overall operation linear in the number of links traversed.
Q12. What happens when Collections.min() is used on an empty collection?
Answer: It throws NoSuchElementException. Check that the collection contains elements before calling min() or max().
26. Quick Revision
Collections.sort(list) sorts using natural ordering.
Collections.sort(list, comparator) sorts using a custom ordering.
Collections.reverseOrder() supplies reverse natural ordering.
Collections.binarySearch(list, key) searches a correctly sorted list.
- A non-negative binary search result indicates a match; a negative result encodes the insertion point.
Collections.min() and Collections.max() find extreme values.
Collections.reverse() reverses the current order.
Collections.shuffle() randomly permutes elements.
Collections.frequency() counts matching elements.
Collections.swap() exchanges two indexed elements.
- Sorting and searching must use compatible comparison rules.
27. Conclusion
Sorting and searching are essential operations when working with Java collections. The Collections utility class provides convenient methods for sorting lists, searching sorted data, reversing and shuffling elements, and calculating basic collection statistics. By understanding natural ordering, custom comparators, binary search requirements, and common exceptions, developers can write clearer and more reliable Java programs.
Practice these methods with numbers, strings, and custom objects to strengthen your understanding of the Java Collections Framework.
Learn More with JustAcademy
Explore the Core Java Training Course to continue learning Java fundamentals, object-oriented programming, collections, exception handling, and other core concepts.
Interested in a course demonstration? Register for a Course Demo.
You can also visit the JustAcademy official website to explore available training programs.