Java Collections Class (Utility Class)

In this guide, we will take a look into the usage of the Collections class, and its methods with examples.

The Java Collections Class is a utility class in java.util package that consists of several static methods that operate on or return collections. It is a member of the Java Collections Framework.

Important Key Points About Collections Class

Here are some key points about the Java Collections Class: 

Utilities: 

The Collections class provides several utility methods like sorting and binary search to manipulate data in collections. 

Algorithms: 

The class includes several algorithms to operate on collections, like shuffle(), sort(), reverse(), rotate(), and swap(). These can be used to perform complex manipulations on collections with a single method call.

Synchronization Wrappers: 

The Collections class provides methods like synchronizedList(), synchronizedSet(), and synchronizedMap() to return synchronized (thread-safe) collections. These methods are useful in multi-threaded environments. 

Unmodifiable Wrappers: 

Methods like unmodifiableList(), unmodifiableSet(), and unmodifiableMap() can be used to make a collection unmodifiable, which is useful for creating an immutable collection. 

Singletons: 

The Collections class offers methods like singletonList(), singletonSet(), and singletonMap() to create an immutable collection with a single element. 

Checked Interfaces: 

The Collections class provides type-safe access to collections with methods like checkedList(), checkedSet(), and checkedMap(). These methods are used to ensure that an instance of a collection doesn't contain elements of a type different than the specified one. 

Finding Extreme Values: 

The max() and min() methods can be used to find the maximum and minimum elements of a collection, respectively. 

Frequency and Disjoint: 

The frequency() method can be used to find the number of times an element occurs in a collection. disjoint() checks if two collections have elements in common. 

Empty and Singleton Collections: 

The Collections class provides methods to return empty collections (emptyList(), emptySet(), emptyMap()) and singleton collections. 

Search Operations: 

The binarySearch() method is used to search for an element in a list, but the list must be sorted before this operation can be used. 

Remember, since all methods of the Collections class are static, they can be called directly without creating an instance of the class.

Important java.util.Collections methods

  • sort(List list)
  • sort(List list, Comparator<? super Project> c)
  • shuffle(List<?> list)
  • reverse(List<?> list)
  • rotate(List<?> list, int distance)
  • swap(List<?> list, int i, int j)
  • replaceAll(List list, String oldVal, String newVal)
  • copy(List<? super String> dest, List<? extends String> src)
  • Collections.binarySearch(list, "element 4")
  • frequency(Collection<?> c, Object o)
  • disjoint(Collection> c1, Collection> c2)
  • min(Collection extends ?> coll)
  • max(Collection extends ?> coll)
We use the above Collections utility class methods to demonstrate the below Algorithms with examples: 
  • Sorting
  • Shuffling
  • Routine Data Manipulation
  • Searching
  • Composition
  • Finding Extreme Values

Sorting using Collections Utility Class

The Collections class provides two overloaded sorting methods:

sort(List list)

This method sorts the specified list into ascending order, according to the natural ordering of its elements. 
All elements in the list must implement a Comparable interface.
Example:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();
        list.add("element 2");
        list.add("element 1");
        list.add("element 4");
        list.add("element 3");
        // Sorts the specified list into ascending order, according to
        // the natural ordering of its elements.
        Collections.sort(list);
        for (String str : list) {
            System.out.println("sort elements in ascending order  --" + str);
        }
    }
}
Output:
 sort elements in ascending order  --element 1
 sort elements in ascending order  --element 2
 sort elements in ascending order  --element 3
 sort elements in ascending order  --element 4

sort(List list, Comparator<? super Project> c)

This method sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the list). 
Example:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class CollectionsClassExamples {

    public static void main(String[] args) {
        sortingCustomObjectsByComparator();
    }

    private static void sortingCustomObjectsByComparator() {
        // Sort Projects by project id in ascending order.
        List<Project> projects = new ArrayList<>();
        Project project = new Project();
        project.setProjectId(100);
        project.setProjectName("TMS");
        projects.add(project);

        Project project2 = new Project();
        project2.setProjectId(200);
        project2.setProjectName("APEX");
        projects.add(project2);

        Project project3 = new Project();
        project3.setProjectId(50);
        project3.setProjectName("CMS");
        projects.add(project3);

        // Sorting project by project name in ascending order in Java
        Collections.sort(projects, Comparator.comparing(Project::getProjectName));
        printList(projects);

    }

    private static void printList(List<Project> projects) {
        for (Project project : projects) {
            System.out.println(project.getProjectId());
            System.out.println(project.getProjectName());
        }
    }

}

class Project implements Comparable<Project> {
    private int projectId;
    private String projectName;

    public int getProjectId() {
        return projectId;
    }

    public void setProjectId(int projectId) {
        this.projectId = projectId;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    @Override
    public int compareTo(Project project) {
        return this.getProjectId() - project.getProjectId();
    }
}
Output:
200
APEX
50
CMS
100
TMS

Shuffling using Collections Utility Class

The shuffle algorithm does the opposite of what sort does, destroying any trace of order that may have been present in a List. That is, this algorithm reorders the List based on input from a source of randomness such that all possible permutations occur with equal likelihood, assuming a fair source of randomness. 
Let's understand the Collections utility class provided the shuffling methods with an example.

shuffle(List<?> list)

This method randomly permutes the specified list using a default source of randomness. All permutations occur with approximately equal likelihood.
Example:
    private static void shuffleAlgorithmsDemo() {
        List<String> list = new LinkedList<>();
        list.add("element 2");
        list.add("element 1");
        list.add("element 4");
        list.add("element 3");

        Collections.sort(list);
        for (String str : list) {
            System.out.println(" sort elements in ascending order  --" + str);
        }

        // randomly permutes the elements in a List.
        Collections.shuffle(list);
        for (String str : list) {
            System.out.println(" sort elements in ascending order  --" + str);
        }
    }
Output:
 sort elements in ascending order  --element 1
 sort elements in ascending order  --element 2
 sort elements in ascending order  --element 3
 sort elements in ascending order  --element 4
 shuffle elements  --element 1
 shuffle elements  --element 3
 shuffle elements  --element 4
 shuffle elements  --element 2

Routine Data Manipulation

The Collections class provides five algorithms for doing routine data manipulation on List objects, all of which are pretty straightforward:
  • reverse - reverses the order of the elements in a List.
  • fill - overwrites every element in a list with the specified value. This operation is useful for reinitializing a List.
  • copy - takes two arguments, a destination List, and a source list, and copies the elements of the source into the destination, overwriting its contents. The destination List must be at least as long as the source. If it is longer, the remaining elements in the destination List are unaffected.
  • swap - swaps the elements at the specified positions in a List.
  • addAll - Adds all the specified elements to a Collection. The elements to be added may be specified individually or as an array.

reverse() Method

This method reverses the order of the elements in the specified list.
Example:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<String> list = new LinkedList<>();
        list.add("element 2");
        list.add("element 1");
        list.add("element 4");
        list.add("element 3");
        
        Collections.sort(list);
        for(String str : list){
             System.out.println("sort elements in ascending order  --" + str);
        }
        //reverses the order of the elements in a List.
        Collections.reverse(list);
        
        for(String str : list){
             System.out.println(" reverse sorted elements  --" + str);
        }
    }
}

Output:

sort elements in ascending order  --element 1
sort elements in ascending order  --element 2
sort elements in ascending order  --element 3
sort elements in ascending order  --element 4
 reverse sorted elements  --element 4
 reverse sorted elements  --element 3
 reverse sorted elements  --element 2
 reverse sorted elements  --element 1

rotate() Method

This method is a built-in method in Java's Collections class that rotates the elements in a specified list by a specified distance. If the distance is positive, the elements are shifted to the right; if the distance is negative, the elements are shifted to the left.
 
Here is an example usage of the rotate method:
import java.util.Arrays;
import java.util.List;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        // Creating an ArrayList
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

        // Displaying elements of original list
        System.out.println("List before rotation: " + list);

        // Using Collections.rotate() to rotate the list by 2 positions to the right
        Collections.rotate(list, 2);

        // Displaying elements of list after rotation
        System.out.println("List after rotation: " + list);
    }
}

Output:

List before rotation: [1, 2, 3, 4, 5]
List after rotation: [4, 5, 1, 2, 3]
In this example, the rotate method is called on an ArrayList of integers with a distance of 2. This means that each element in the list is moved two positions to the right. The elements at the end of the list wrap around the beginning of the list.

swap() Method

This method is a built-in method in Java's Collections class that swaps the elements at the specified positions in the specified list. 

Here is an example usage of the swap method:
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        // Create an ArrayList
        ArrayList<String> list = new ArrayList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");

        // Displaying elements of original ArrayList
        System.out.println("ArrayList before the Swap:");
        for(String str: list){
            System.out.println(str);
        }

        // Using swap() method to swap elements of ArrayList
        Collections.swap(list, 1, 4);

        System.out.println("\nArrayList after the Swap:");
        for(String str: list){
            System.out.println(str);
        }
    }
}

Output:

ArrayList before the Swap:
A
B
C
D
E

ArrayList after the Swap:
A
E
C
D
B
In this example, the swap method is used to swap the elements at index 1 and index 4 in an ArrayList of Strings. After the swap, the element that was originally at index 1 is now at index 4 and vice versa.

replaceAll() Method

This method replaces all occurrences of one specified value in a list with another. 
Example:
import java.util.*;

public class Main {
    public static void main(String[] args) {

        List<String> list = new LinkedList<>();
        list.add("element 2");
        list.add("element 1");
        list.add("element 4");
        list.add("element 3");
        
        //replaces all occurrences of one specified value with another.
        Collections.replaceAll(list, "element 3", "element 6");

        // Displaying elements of list after replace
        System.out.println("List after replace element 6: " + list);
    }
}

Output:

List after replace element 6: [element 2, element 1, element 4, element 6]

copy()

This method is a built-in method in Java's Collections class that copies all elements from one list into another. The destination list needs to be large enough to accommodate all elements from the source list, otherwise an IndexOutOfBoundsException will be thrown.
Example:
import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        // Create a source list
        ArrayList<String> src = new ArrayList<String>();
        src.add("A");
        src.add("B");
        src.add("C");

        // Create a destination list with enough capacity
        ArrayList<String> dest = new ArrayList<String>();
        dest.add("");
        dest.add("");
        dest.add("");

        // Displaying elements of original lists
        System.out.println("Source List: " + src);
        System.out.println("Destination List (Before Copy): " + dest);

        // Use Collections.copy() method to copy elements
        Collections.copy(dest, src);

        System.out.println("Destination List (After Copy): " + dest);
    }
}

Output:

Source List: [A, B, C]
Destination List (Before Copy): [, , ]
Destination List (After Copy): [A, B, C]

Searching using Collections Utility Class

The binary search algorithm searches for a specified element in a sorted list. This algorithm has two forms:
  • The first takes a List and an element to search for (the "search key"). This form assumes that the list is sorted in ascending order according to the natural ordering of its elements.
  • The second form takes a Comparator in addition to the List and the search key and assumes that the list is sorted into ascending order according to the specified Comparator.
Example: Let's use the sort() method to sort the List prior to calling binarySearch:
private static void searchingAlgorithmsDemo() {
    List<String> list = new LinkedList<>();
    list.add("element 2");
    list.add("element 1");
    list.add("element 4");
    list.add("element 3");
 
    Collections.sort(list);
    for (String str : list) {
        System.out.println(" sort elements in ascending order  --" + str);
    }
    int index = Collections.binarySearch(list, "element 4");
    System.out.println("Element found at ::" + index);
}
Output:
 sort elements in ascending order  --element 1
 sort elements in ascending order  --element 2
 sort elements in ascending order  --element 3
 sort elements in ascending order  --element 4
 Element found at ::3

Composition

The frequency and disjoint algorithms test some aspects of the composition of one or more Collections:
  • frequency - counts the number of times the specified element occurs in the specified collection.
  • disjoint - determines whether two Collections are disjoint; that is, whether they contain no elements in common.

frequency() Method

This method returns the number of elements in the specified collection equal to the specified object. 
Example:
List<String> list = new LinkedList<>();
list.add("element 2");
list.add("element 1");
list.add("element 1");
list.add("element 3");
//Returns the number of elements in the specified collection         
//equal to the specified object.
System.out.println(Collections.frequency(list, "element 1"));

disjoint() Method

This method returns true if the two specified collections have no elements in common.
Example:
List<String> list = new LinkedList<>();
list.add("element 2");
list.add("element 1");
list.add("element 1");
list.add("element 3");
//Returns the number of elements in the specified collection         
//equal to the specified object.

System.out.println(Collections.frequency(list, "element 1"));
List<String> list2 = new LinkedList<>();
list2.add("element 2");
list2.add("element 1");
list2.add("element 1");
list2.add("element 3");
//Returns true if the two specified collections have no elements in common. 
System.out.println(Collections.disjoint(list, list2));

Finding Extreme Values(min and max methods)

The min and the max algorithms return, respectively, the minimum and maximum elements contained in a specified Collection. Both of these operations come in two forms. 
The simple form takes only a Collection and returns the minimum (or maximum) element according to the elements' natural ordering. 
The second form takes a Comparator in addition to the Collection and returns the minimum (or maximum) element according to the specified Comparator.

min() Method

This method returns the minimum element of the given collection, according to the natural ordering of its elements. All elements in the collection must implement a Comparable interface. 
Example:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new LinkedList<>();
        list.add(100);
        list.add(300);
        list.add(200);
        list.add(500);
        System.out.println("Minimun element in the list: " + Collections.min(list));
    }
}

Output:

Minimun element in the list: 100

max() Method

This method returns the maximum element of the given collection, according to the natural ordering of its elements. All elements in the collection must implement a Comparable interface. 
Example:
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = new LinkedList<>();
        list.add(100);
        list.add(300);
        list.add(200);
        list.add(500);
        System.out.println("Maximum element in the list: " + Collections.max(list));
    }
}

Output:

Maximum element in the list: 500

References

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/java/util/Collections.html

Comments