Collection Readonly
## Creating Read-Only Collections in Java
In Java, there are many scenarios where you want to expose a collection to other parts of your application but prevent them from modifying its contents. Making a collection read-only (or unmodifiable) is an excellent way to enforce encapsulation, ensure thread safety for shared data, and prevent accidental bugs.
This tutorial demonstrates how to use the `java.util.Collections` utility class to create read-only views of Lists, Sets, and Maps.
---
## Understanding Unmodifiable Collections
The `java.util.Collections` class provides static wrapper methods that return an unmodifiable view of a specified collection.
### Key Characteristics:
* **Read-Only View:** Any attempt to modify the returned collection (such as adding, removing, or updating elements) will throw an `UnsupportedOperationException`.
* **Backed by the Original Collection:** The returned collection is not a separate copy; it is a wrapper around the original collection. If the original collection is modified, those changes will still be reflected in the read-only view.
* **Shallow Immutability:** The collection structure itself is read-only, but if the elements inside the collection are mutable objects, their internal states can still be modified.
---
## Syntax and Methods
The `Collections` class provides the following primary methods to create read-only wrappers:
```java
public static List unmodifiableList(List extends T> list)
public static Set unmodifiableSet(Set extends T> set)
public static Map unmodifiableMap(Map extends K, ? extends V> m)
```
---
## Code Example
The following example demonstrates how to create read-only versions of a `List`, `Set`, and `Map`. It also shows how the collection throws an `UnsupportedOperationException` when a write operation is attempted.
### `Main.java`
```java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Main {
public static void main(String[] argv) throws Exception {
// 1. Create a mutable list and wrap it as read-only
List stuff = Arrays.asList(new String[] { "a", "b" });
List list = new ArrayList<>(stuff);
list = Collections.unmodifiableList(list);
// Attempting to modify the read-only list
try {
list.set(0, "new value"); // This will fail
} catch (UnsupportedOperationException e) {
System.out.println("Notice: Modification blocked! The List is read-only.");
}
// 2. Create a read-only Set
Set set = new HashSet<>(stuff);
set = Collections.unmodifiableSet(set);
// 3. Create a read-only Map
Map map = new HashMap<>();
map.put("key1", "value1");
map = Collections.unmodifiableMap(map);
System.out.println("Collections are now configured as read-only.");
}
}
```
### Output
```text
Notice: Modification blocked! The List is read-only.
Collections are now configured as read-only.
```
---
## Important Considerations
### 1. Unmodifiable vs. Immutable
* **Unmodifiable:** The collection wrapper cannot be modified directly. However, if you still hold a reference to the underlying mutable collection, you can modify it, and the "read-only" wrapper will change.
* **Immutable:** The collection cannot be modified under any circumstances.
If you want true immutable collections, consider using Java 9+ factory methods or third-party libraries:
* **Java 9+:** Use `List.of()`, `Set.of()`, or `Map.of()`.
* **Guava:** Use `ImmutableList`, `ImmutableSet`, or `ImmutableMap`.
### 2. Element Mutability
Making a collection read-only does not make its elements immutable. For example:
```java
List users = new ArrayList<>();
users.add(new User("Alice"));
List readOnlyUsers = Collections.unmodifiableList(users);
// This is blocked:
// readOnlyUsers.add(new User("Bob"));
// This is allowed (if User has a setter):
readOnlyUsers.get(0).setName("Bob");
```
To ensure complete immutability, the objects stored inside the collection must also be immutable.
YouTip