Appearance
Collections
Collections
is a utility class provided by the JDK, also located in the java.util
package. It offers a series of static methods that facilitate operations on various collections.
Note
The name is Collections
, not Collection
!
We can generally determine the functionality of a method provided by Collections
from its name and parameters. For example, for the following static method:
java
public static boolean addAll(Collection<? super T> c, T... elements) { ... }
The addAll()
method can add several elements to a collection of type Collection
. Since the method signature is Collection
, we can pass in various collection types such as List
, Set
, etc.
Creating Empty Collections
For older versions of the JDK, you can use the following methods provided by Collections
to create empty collections:
- Create an empty List:
List<T> emptyList()
- Create an empty Map:
Map<K, V> emptyMap()
- Create an empty Set:
Set<T> emptySet()
It's important to note that the returned empty collections are immutable, meaning you cannot add or remove elements from them.
In newer versions of the JDK (≥9), you can directly use List.of()
, Map.of()
, and Set.of()
to create empty collections.
Creating Single-Element Collections
For older versions of the JDK, Collections
provides methods to create single-element collections:
- Create a single-element List:
List<T> singletonList(T o)
- Create a single-element Map:
Map<K, V> singletonMap(K key, V value)
- Create a single-element Set:
Set<T> singleton(T o)
It’s worth noting that the returned single-element collections are also immutable.
In newer versions of the JDK (≥9), you can directly use List.of(T...)
, Map.of(T...)
, and Set.of(T...)
to create collections with any number of elements.
Sorting
Collections
can sort a List
. Since sorting directly modifies the position of elements in the List
, you must pass a mutable List
:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("pear");
list.add("orange");
// Before sorting:
System.out.println(list);
Collections.sort(list);
// After sorting:
System.out.println(list);
}
}
Shuffling
Collections
also provides a shuffle algorithm. You can pass an ordered List
, which randomly rearranges the order of its internal elements, effectively shuffling the list:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
// Before shuffling:
System.out.println(list);
// Shuffle:
Collections.shuffle(list);
// After shuffling:
System.out.println(list);
}
}
Immutable Collections
Collections
also provides a set of methods to wrap mutable collections into immutable collections:
- Wrap into an immutable List:
List<T> unmodifiableList(List<? extends T> list)
- Wrap into an immutable Set:
Set<T> unmodifiableSet(Set<? extends T> set)
- Wrap into an immutable Map:
Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m)
This wrapping is done by creating a proxy object that intercepts all modification methods. Let’s see the effect:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> mutable = new ArrayList<>();
mutable.add("apple");
mutable.add("pear");
// Convert to immutable collection:
List<String> immutable = Collections.unmodifiableList(mutable);
immutable.add("orange"); // UnsupportedOperationException!
}
}
However, continuing to modify the original mutable List
is still allowed, and it will directly affect the wrapped "immutable" List
:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> mutable = new ArrayList<>();
mutable.add("apple");
mutable.add("pear");
// Convert to immutable collection:
List<String> immutable = Collections.unmodifiableList(mutable);
mutable.add("orange");
System.out.println(immutable);
}
}
Therefore, if we want to wrap a mutable List
into an immutable List
, it's best to immediately discard the reference to the mutable List
after returning the immutable List
. This way, we can ensure that subsequent operations won’t inadvertently change the original object, leading to modifications in the "immutable" List
:
java
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> mutable = new ArrayList<>();
mutable.add("apple");
mutable.add("pear");
// Convert to immutable collection:
List<String> immutable = Collections.unmodifiableList(mutable);
// Immediately discard reference to mutable:
mutable = null;
System.out.println(immutable);
}
}
Thread-Safe Collections
Collections
also provides a set of methods to turn non-thread-safe collections into thread-safe ones:
- Convert to a thread-safe List:
List<T> synchronizedList(List<T> list)
- Convert to a thread-safe Set:
Set<T> synchronizedSet(Set<T> s)
- Convert to a thread-safe Map:
Map<K, V> synchronizedMap(Map<K, V> m)
We will discuss the concept of multithreading later. Since Java 5 introduced more efficient concurrent collection classes, the above synchronization methods have become less useful.
Summary
The Collections
class provides a set of utility methods to facilitate the use of collection classes:
- Create empty collections.
- Create single-element collections.
- Create immutable collections.
- Perform operations like sorting and shuffling.