Set.of 和 HashSet 常被开发者一同提及,但很多人对它们之间的本质差异感到困惑。简单来说:Set.of 创建的是不可变集合,虽然自带去重功能,但它并不是基于 HashSet 实现的,也绝不允许修改或传入 null。如果你想要一个“不可变的 HashSet”,就需要先手动构建一个 HashSet,再套一层不可变封装,或者直接用 Guava 的 ImmutableSet。

Set.of 创建的是不可变集合,它本身不基于 HashSet 实现,也不支持重复元素(自动去重),但你不能通过它“构建 HashSet”——因为 Set.of 返回的是不可变的 Set 实现类(如 ImmutableSet),而非 HashSet 实例。
Set.of 本质是不可变集合,不是 HashSet
Set.of(...) 是 Java 9 引入的工厂方法,返回一个轻量级、不可修改的 Set。其底层实现根据元素个数选择不同类(例如 0–10 个元素用内部静态类,更多时用 ImmutableCollections.SetN),但绝不是 HashSet。它不接受 null,不允许添加/删除/修改,且自动去重——重复元素会被忽略,只保留一个。
Set.of("a", "b", "a")→ 包含"a"和"b"(去重成功)Set.of("a", "b", "a").add("c")→ 抛出UnsupportedOperationExceptionSet.of("a", "b", "a") instanceof HashSet→false
如果需要不可变 + 基于 HashSet 的语义,得手动转换
假设你明确需要一个“底层行为类似 HashSet”的不可变集合——比如哈希查找、无序、允许自定义对象需重写 hashCode/equals——那不能直接用 Set.of 得到 HashSet,但可以走两条路:
- 先用
new HashSet(...)构建可变集合(完成去重和初始化) - 再用
Collections.unmodifiableSet(...)封装为不可变视图 - 或者使用 Guava 的
ImmutableSet.copyOf(...)(更安全,真正不可变)
示例:
Set immutable = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("a", "b", "a")));
Set.of 的去重规则和限制
它按 equals 判断重复,要求所有元素非 null,且必须满足 equals/hashCode 合约。对自定义类,仍需正确重写这两个方法;否则去重可能失效。
- 重复字面量(如
"hello")会自动合并 - 两个不同对象但
equals为 true → 视为重复,只留其一 - 传入 null → 直接抛
NullPointerException
什么时候该用 Set.of?
它适合创建小规模、固定、已知内容的不可变去重集合,比如配置常量、枚举替代、临时校验集合等。轻量、线程安全、创建快。但如果你需要动态构建、大集合,或者想控制 HashSet 特有的容量、负载因子,那还是老老实实用 new HashSet 加不可变封装吧。
