The Utility Class Collections
The Java Collections Framework includes the Collections
utility class that contains a number of static methods for creating and processing collections. Some of the methods represent generic algorithms, which means they can work with different types of collections.
It is often the case that programmers forget about this class and reinvent its methods from scratch in their source code. Obviously, it's better to remember about this class and check whether it contains the operations you need to perform with a collection.
Let's consider some groups of the provided methods. The full list of the method is available in the official documentation.
Please, do not confuse the Collections
class and the Collection
interface. They both belong to the java.util
package but represent completely different things.
Creating immutable collections
The first group is a set of methods for creating empty and single-element immutable collections.
List<String> emptyList = Collections.emptyList();
Set<Integer> emptySet = Collections.emptySet();
List<Integer> singletonList = Collections.singletonList(100);
Set<String> singletonSet = Collections.singleton("Hello");
Using these methods look pretty straightforward. But why do we need empty and single element collections? For example, empty collections are often used as the return values from methods instead of null
to avoid NPE.
public static Collection<Integer> algorithm(Collection<Integer> numbers) {
// lots of lines of code
if (some_condition) {
return Collections.emptyList(); // instead of null
}
// lots of lines of code
}
Singleton collections are extremely optimized to work with a single value. As an example, the class SingletonList<E>
looks like this:
class SingletonList<E> extends .. implements ... {
private final E element; // storing a single element
SingletonList(E obj) {
element = obj;
}
// some fields and methods
}
Apart from this, the class also provides methods to create immutable collections from other collections:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(12);
List<Integer> immutableList = Collections.unmodifiableList(numbers);
There are similar methods: unmodifiableSet(set)
and more.
Remember that it's impossible to change elements within immutable collections. Methods that change elements (add
, clear
and so on) will throw UnsupportedOperationException
when being invoked.
List<Integer> singletonList = Collections.singletonList(10);singletonList.add(20); // throws UnsupportedOperationException
Starting with Java 9, there is an alternative way to create immutable collections: List.of()
, List.of(1, 2)
, Set.of("Hello")
. But it is still useful to know about the previous way of doing that, since it is often present in existing code.
We skipped the methods for creating maps, but they look very similar. If you need them, just look into the documentation.
Processing lists
There are also some methods for performing list-specific operations: sorting, reversing, rotating, and shuffling lists.
Check them out on the following example:
var numbers = new ArrayList<>(List.of(1, 2, 3, 2, 3, 4)); // getting a mutable list
Collections.sort(numbers); // [1, 2, 2, 3, 3, 4]
Collections.reverse(numbers); // [4, 3, 3, 2, 2, 1]
Collections.shuffle(numbers); // randomly permutes the list
System.out.println(numbers); // a result can be any: [4, 2, 3, 2, 3, 1]
The rotate
method shifts the elements in the specified list by the given distance.
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3, 2, 3, 4));
Collections.rotate(numbers, 1); // [4, 1, 2, 3, 2, 3]
Collections.rotate(numbers, 2); // [2, 3, 4, 1, 2, 3]
These methods can be very useful in many applications. The listed methods have overloaded versions as well.
Calculations on collections
There are some methods that can be applied to any collections since the methods take a Collection
interface as an argument.
frequency
counts the number of elements equal to a specified object;min
andmax
finds the minimum and maximum elements according to the natural order of elements;disjoint
checks that the two collections do not contain common elements.
Here is an example of applying the listed methods.
List<Integer> numbers = List.of(1, 2, 3, 2, 3, 4);
System.out.println(Collections.frequency(numbers, 3)); // 2
System.out.println(Collections.min(numbers)); // 1
System.out.println(Collections.max(numbers)); // 4
System.out.println(Collections.disjoint(numbers, List.of(1, 2))); // false
System.out.println(Collections.disjoint(numbers, List.of(5, 6))); // true
If the collection is empty, the methods min
and max
will throw NoSuchElementException
. But frequency
will just return 0.
The Collections
class contains some other methods for working with collections as well.
A tricky example
We would like to demonstrate one tricky and interesting example with some modifying operations on immutable collections. Just take a look at the following code examples:
List<Integer> singletonList = Collections.singletonList(1);
Collections.sort(singletonList); // it doesn't throw an exception
Collections.shuffle(singletonList); // it doesn't throw an exception
List<Integer> numbers = Collections.unmodifiableList(List.of(2, 1, 3));
Collections.shuffle(numbers); // it throws UnsupportedOperationException
The first and second operations work without throwing an exception since a list containing only a single element doesn't require any modifications to be sorted or shuffled unlike the list with three elements. But if you replace Collections.singletonList(1)
with List.of(1)
, the first and second operations will also fail. Even immutable collections have behavioral peculiarities.
In order not to confuse other programmers, it's better not to rely on such somewhat counterintuitive features of Java in your programming solutions, even if they are fun enough. Over time, you will also forget why such code works.
Conclusion
the Java Collections
class is an essential tool for working with collections in Java. It provides a variety of static methods to create and manipulate collections efficiently, often saving developers from reinventing the wheel. By leveraging methods like emptyList()
, singletonList()
, and unmodifiableList()
, developers can ensure that their code handles immutable collections safely and effectively. Additionally, the utility methods for processing lists, such as sorting, shuffling, and rotating, offer practical solutions for common tasks.
Overall, the Collections
class is a powerful tool that, when used properly, can simplify many common collection-related tasks and improve the performance of Java applications. By leveraging its features, developers can write more readable and maintainable code, making it easier to understand and modify in the future. As one of the core utilities in the Java programming language, the Collections
class offers a wide range of methods that can handle a variety of use cases, ultimately enhancing both the efficiency and clarity of your code.