`Collections.unmodifiableXYZ()` methods expose collection views that callers must treat as read-only. The central mistake is assuming that a collection returned by a method can be modified: calling `add`, `remove`, or similar operations may fail when the result is unmodifiable. Make a separate copy when mutation is required, and document the exceptional APIs that deliberately return mutable collections. section 8.5
Return one mutability contract
Avoid APIs that return a mutable list on one path and an unmodifiable list on another. A caller of `sanitize(input)` may reasonably try `strings.add("Custom...")`; that breaks if an empty-input path returns `Collections.emptyList()` while another path returns an `ArrayList`. Prefer a consistently unmodifiable result, such as `List.copyOf(data)`, or explicitly promise mutability. section 8.5
Use unmodifiable collection APIs defensively:
- Assume collections returned from other methods are unmodifiable unless their API explicitly promises mutation. section 8.5
- Copy a returned collection before changing it rather than attempting to modify the returned value. section 8.5
- Return unmodifiable results from public methods with `Collections.unmodifiableXYZ()`, collection factories such as `List.of()` and `List.copyOf()`, or unmodifiable stream collectors. section 8.5
- Avoid mutating collection parameters in public APIs unless mutability is an explicit input requirement. section 8.5
Choose the specific wrapper when collection semantics matter. `unmodifiableCollection(list)` does not itself implement `List`, so its `equals()` cannot compare equal to a list under the `List.equals()` contract; symmetry requires the reverse comparison to be false too. `unmodifiableList()` and `unmodifiableSet()` preserve content-based equality appropriate to their respective interfaces. section 7.2
public static <T> List<T> unmodifiableList(List<? extends T> list)
`unmodifiableList` accepts `List<? extends T>` and returns `List<T>`. Besides preventing writes through the result, this can adapt a list of a more specific element type to a read-only list of a more abstract type, avoiding an unchecked cast at a call site. section 5.3.2
For stream results, `Collectors.toList()` yields a de-facto modifiable collection but does not guarantee that property. Use `Collectors.toUnmodifiableList()` when an unmodifiable result is intended; since Java 16, `Stream.toList()` also produces an unmodifiable list. section 8.5
