Collections Utility Class - Sip of Java
Billy Korando on June 11, 2023The 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.
Binary Search
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 List
s 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
Happy coding!