Java的of()系列方法强制拒绝null,是硬性契约而非建议;可作入参校验器,配合@NotNull注解和不可变容器设计,构建编译期与运行期双重空安全防线。

Java 的 List.of()、Set.of()、Map.of() 等不可变集合工厂方法,从设计上就拒绝 null——这不是建议,而是硬性契约。一旦传入 null,立刻抛出 NullPointerException,且堆栈指向调用点,不进深层逻辑。这本身就是一道天然的「入参红线」,关键在于如何把它用成真正可靠的安全防线。
把 of 方法当「校验器」用,而非仅当容器创建工具
很多人只把 List.of(a, b, c) 当作快捷写法,却忽略它自带的空值拦截能力。只要参数里有 null,运行时直接失败,比手写 if (x == null) 更早暴露问题。
- 适用于明确要求所有元素非空的场景:比如初始化配置项列表、构建枚举映射键值对、组装固定参数集合
- 不适用于需容忍部分空值的动态数据(如数据库查询结果),此时应先过滤或转为
Optional处理 - 错误示范:
List.of(user.getName(), user.getEmail(), user.getPhone())—— 若任一字段为null,立即炸;正确做法是先校验或使用安全包装
配合 @NotNull + 编译期检查,把红线前移到编码阶段
@NotNull 注解(来自 javax.validation.constraints 或 JetBrains)本身不运行,但和 IDE、Lombok、构建插件联动后,能提前标出风险。
- 在方法参数上标注
@NotNull List<string> names</string>,IDE 会提示你传List.of(...)是安全的,而传Arrays.asList(null, "b")会预警 - Lombok 的
@RequiredArgsConstructor配合@NonNull字段,自动生成Objects.requireNonNull,与of()的空值拦截形成双重保障 - 注意:
of()拦的是集合元素,@NotNull拦的是集合引用本身——两者互补,不重叠
用 of() 构建不可变入参容器,切断外部篡改路径
接收可变集合(如 ArrayList)作为参数,意味着调用方可能在你处理中途修改它;而用 of() 创建的集合天生不可变,也天然不含 null。
- 推荐接口定义:
void processRoles(List<string> roles)</string>→ 改为void processRoles(List<string> roles)</string>,并在实现开头加roles = List.copyOf(roles)或直接要求传List.of(...) - 若必须接受外部集合,优先转为不可变副本:
List.copyOf(inputList)(JDK 10+)会做空值检查并复制,比Collections.unmodifiableList更安全 - 禁止将
of()结果再转回可变类型(如new ArrayList(List.of(...))),否则失去防线意义
警惕「假安全」组合:of() 和 null 元素共存的常见破防点
of() 的空值拦截非常严格,但开发者常因疏忽绕过它:
- 误用
Arrays.asList(null)后再传给of():错!Arrays.asList允许null,of()才真正拦截,但此时已晚一步 - 用
stream().collect(Collectors.toList())聚合含null的流,再喂给of():同样失效,需先filter(Objects::nonNull) - Map 场景更隐蔽:
Map.of(key, null)直接报错,但Map.ofEntries(entry1, entry2)中某个entry.getValue()为null也会触发异常

















