=== List.of(...) - rejects null at construction time === List.of("a", null, "c") threw NullPointerException === Arrays.asList(...) - allows null, it's just a view over the array === Arrays.asList("a", null, "c") = [a, null, c] === Collections.unmodifiableList(...) - allows whatever the backing list allows === unmodifiableList over a list already containing null = [a, null, c] (it has no null-check of its own - it only blocks structural writes, see below) === List.copyOf(...) - rejects null, same as List.of === List.copyOf(aListContainingNull) threw NullPointerException -> List.copyOf() re-validates elements, it does not just wrap and trust the source === Collections.unmodifiableList is a VIEW, not a copy: mutating the backing list shows through === before: unmodView = [a, null, c] after backing.set(0,...) and backing.add("d"): unmodView = [A-CHANGED, null, c, d] -> the "unmodifiable" promise is about the VIEW's own mutator methods, not about the data being frozen === unmodifiableList's own mutators still throw, even though the backing list is mutable === unmodView.add("e") threw UnsupportedOperationException