Collections Utility Class - Sip of Java

The Collections Utility class was added in JDK 1.2 and was most recently updated in JDK 8. The Collections Utility class provides an API for working with classes in the Collections framework; Collections, Lists, Maps, and Sets. Let’s take a look.

💡 Note: that examples in this article use a List, but in most cases, complementary methods exist for Map, Set, Collection, and other classes in the Collection Framework. For brevity, only the List example is shown.

Searching Collections

Among the most common operations on collections is searching their contents. Here the Collections Utility provides several options.

Collections provides options for executing a binary search on a sorted collection:

List<String> advocates = List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai");
Collections.binarySearch(advocates, "Billy");//1

Min/Max

If all the items of a collection implement Comparable, Collections has min() and max() for finding the lowest values and max value of the collection based on natural ordering, respectively:

List<String> advocates = List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai");
Collections.max(advocates);//Nicolai
Collections.min(advocates);//Ana

Frequency

Collections can search for the number of times an item exists in a collection with frequency:

List<String> advocates = List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai");
Collections.frequency(advocates, "Denys");//1

Comparing Collections

Collections also has options for comparing two Lists for matches. There is indexOfSubList(), which will return the index of the first instance when a sub-list matches the target List, and lastIndexOfSubList(), which does the same, but for the last occurrence. In both cases, -1 will be returned if no match is found.

There is also disjoint(), which compares the items contained within two collections. true will be returned if there are no items in common between the two collections, and false if any item from one collection appears in the target collection. Examples of all are below:

List<String> advocates = List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai");
List<String> doubleAdvocates = List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai",
		"Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai");
List<String> managers = List.of("Chad", "David", "Sharat");
List<String> someAdvocates = List.of("Denys", "Heather");
Collections.indexOfSubList(doubleAdvocates, someAdvocates);//2 (finds first occurrence) 
Collections.lastIndexOfSubList(doubleAdvocates, someAdvocates);//7 (finds last occurrence) 
Collections.disjoint(advocates, someAdvocates);//false
Collections.disjoint(advocates, managers);//true

Adding to and Copying Collections

For adding to, copying, or in some cases creating collections, the Collections Utility has several solutions.

Add All

To add multiple items to a collection, there is addAll(). The benefit of this addAll() over the addAll() implemented with most Collection types is the null safety:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.addAll(advocates, "Jack", "Jill");//Nicolai, Nicolai, Nicolai, Nicolai, Nicolai, Nicolai, Jack, Jill

Copying

The Collections Utility can also copy the contents of one collection into another. The target collection needs to be the same size or larger than the source collection:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
List<String> advocatesCopy = new ArrayList<>(List.of("Blank","Blank","Blank","Blank","Blank","Blank", "Blank"));
Collections.copy(advocatesCopy, advocates);//Ana, Billy, Denys, Heather, Jim, Nicolai, Blank

n Copies

Collections can be used to create an immutable List filled with n copies of passed value:

List<String> copies = Collections.nCopies(3, "Billy");//Billy, Billy, Billy

Fill

Collections with fill() can fill all the values in an existing collection with the passed-in value:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.fill(advocates, "Billy");//Billy, Billy, Billy, Billy, Billy, Billy

Replace

If you need to replace specific values in a List, there is replaceAll(), which will replace all instances of the target value with the replacement value:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.replaceAll(advocates, "Billy", "Nicolai");//Nicolai, Nicolai, Nicolai, Nicolai, Nicolai, Nicolai

Reordering Collections

If you need to change the order of a Collection, the Collections Utility has many options.

Sort

To sort a collection in its natural ordering, there is: sort(Collection). All items in the collection must implement Comparable. Alternatively, sort(Collection, Comparable) can be used if the items don’t implement Comparable or a different ordering is desired. There is also the complementary reverseOrder() and Collections.reverseOrder(Comparable) which inverts the natural ordering. Finally there is also reverse(Collection):

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.sort(advocates);//Ana, Billy, Denys, Heather, Jim, Nicolai
Collections.sort(advocates, Collections.reverseOrder());//Nicolai, Jim, Heather, Denys, Billy, Ana
Comparator<String> reverseString = new Comparator<String>() {
	@Override
	public int compare(String o1, String o2) {return o2.compareTo(o1);}
};
Collections.sort(advocates, Collections.reverseOrder(reverseString));//Ana, Billy, Denys, Heather, Jim, Nicolai Collections.reverse(advocates);//Nicolai, Jim, Heather, Denys, Billy, Ana

Rotate

Collections can also rotate a List by index like in the example below:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.rotate(advocates, 3);//Heather, Jim, Nicolai, Ana, Billy, Denys

Swap

If the position of specific items needs to be changed, that can be done with swap():

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.swap(advocates, 0, advocates.size() -1);//Nicolai, Billy, Denys, Heather, Jim, Ana

Shuffle

Collections can also be used to randomly reorder a List with shuffle():

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));
Collections.shuffle(advocates, new Random());// [non-stable order]

Converting Collections

Collections can also assist in converting collections from one type to another type.

Checked

A collection can be converted into a Checked version which provides additional guarantees beyond what is provided by the generics system that only items of the assigned type of a collection can be added:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));

Collections.checkedList(advocates, String.class);

Enumeration

Collections can be converted in an Enumeration with enumeration():

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));

Collections.enumeration(advocates);

Unmodifiable

Collections provides unmodifiableX() methods for creating an unmodifiable view of the provided collection. If there are changes made to the provided collection, then they might show up in the view:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));

Collections.unmodifiableList(advocates);

Synchronized

Collections can also provide a synchronized implementation of the associated collection type:

List<String> advocates = new ArrayList<>(List.of("Ana", "Billy", "Denys", "Heather", "Jim", "Nicolai"));

Collections.synchronizedList(advocates);

💡 Note: Using synchronized collection implementations isn’t a problem with virtual threads as they only guard in-memory actions, not I/O or other external calls, which are typically (much) lengthier.

Empty

Collections can also create an unmodifiable empty collection, which can be helpful if needed to fulfill a method argument requirement:

Collections.emptyList();

Other Methods

The Collections Utility offers a few methods that don’t fit neatly into the categories above. Still, they might be worth checking out:

Collections.asLifoQueue(Deque);
Collections.singleton(T);
Collections.singletonList(T);
Collections.singletonMap(K, V);
Collections.newSetFromMap(Map<E, Boolean>);

Additional Reading

Collections Utility JDK 20 JavaDoc

The Collections Framework

Happy coding!