1. 概述

本文将系统介绍在 Java 中创建 HashSet 时如何同时初始化元素的多种方法,适合需要快速查阅初始化技巧的开发者。

如果你更关注 HashSet 本身的特性(比如性能、去重机制等),可以参考我们另一篇核心文章:Java HashSet 详解

我们将从以下几个方面展开:

✅ Java 5 及更早版本提供的原生方式
✅ Java 8 引入 Stream 后的新玩法
✅ 自定义工具方法提升复用性
✅ 第三方集合库(如 Google Guava)的优雅方案
✅ JDK9+ 用户的简单选择:集合工厂方法

💡 提示:如果你的项目已经升级到 JDK9 或更高版本,最简单粗暴的方式其实是直接使用 Set.of("a", "b", "c")。但本文重点覆盖低版本 JDK 的兼容方案,适用于尚未升级的项目。


2. Java 原生方法(Java 5 及之前)

以下是三种从 Java 5 就支持的初始化方式,无需额外依赖。

2.1 使用已有集合实例

通过构造函数传入另一个集合(如 List),是最常见且安全的方式之一。

Set<String> set = new HashSet<>(Arrays.asList("a", "b", "c"));

✅ 优点:简洁、无性能陷阱
⚠️ 注意:Arrays.asList() 返回的是固定大小的 List,不能增删,但这里只是用于初始化 HashSet,没问题

2.2 匿名内部类 + 实例初始化块(双大括号)

利用匿名类和实例初始化块(double brace)语法:

Set<String> set = new HashSet<String>(){{
    add("a");
    add("b");
    add("c");
}};

❌ 踩坑警告:

  • 每次调用都会创建一个新的匿名类,增加类加载开销
  • 序列化时可能导致问题(携带外部类引用)
  • 性能敏感场景务必避免

📌 结论:虽然写起来爽,但属于“看起来很美”的反模式,生产环境慎用。

2.3 使用 Collections 工具类(单元素场景)

Java 提供了 Collections.singleton(T obj) 方法,用于快速创建只含一个元素的不可变 Set:

Set<String> set = Collections.singleton("a");

✅ 适用场景:

  • 单元测试中 mock 返回值
  • 配置常量、标志位等固定单值

⚠️ 注意:返回的是 immutable Set,调用 add() 会抛 UnsupportedOperationException


3. 自定义工具方法

如果项目中频繁需要创建带初始值的 HashSet,建议封装一个泛型工具方法。

public static final <T> Set<T> newHashSet(T... objs) {
    Set<T> set = new HashSet<>();
    Collections.addAll(set, objs);
    return set;
}

使用方式:

Set<String> set = newHashSet("a", "b", "c");

✅ 优势分析:

  • ✅ 支持变长参数,调用简洁
  • ✅ 使用 Collections.addAll,底层是数组拷贝,效率高
  • ✅ 泛型设计,类型安全
  • ✅ 返回可变 Set,后续可修改

💡 建议:把这个方法放在项目的 CollectionUtilsSets 工具类中,团队共用。


4. 使用 Stream(Java 8+)

Java 8 引入 Stream 后,可以通过 Stream.of + Collectors.toCollection 实现灵活初始化:

Set<String> set = Stream.of("a", "b", "c")
  .collect(Collectors.toCollection(HashSet::new));

✅ 优势:

  • 可结合 filter、map 等操作做预处理
  • 函数式风格,适合链式调用
  • 易于扩展(比如从数组/数据库记录构建)

❌ 缺点:

  • 相比直接构造略重,小数据量无感,高频调用需权衡

🎯 适用场景:需要对数据做转换或过滤后再构建成 Set 的情况。


5. 使用第三方集合库

5.1 Google Guava

Guava 是 Java 社区最流行的集合扩展库之一,Maven 依赖如下:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

创建可变 Set

Set<String> set = Sets.newHashSet("a", "b", "c");

创建不可变 Set(推荐用于常量)

Set<String> set = ImmutableSet.of("a", "b", "c");

✅ Guava 优势:

  • API 设计优雅,命名清晰
  • ImmutableSet 性能优于 Collections.unmodifiableSet
  • 提供更多高级集合操作(差集、交集等)

📌 社区共识:Guava 的 ImmutableSet 是创建不可变集合的事实标准

5.2 其他可选库

  • Apache Commons CollectionsCollectionUtils 工具丰富,但初始化语法不如 Guava 直观
  • Eclipse Collections:函数式风格更强,适合大数据处理场景

推荐优先考虑 Guava,生态成熟,文档齐全。


6. 总结与建议

方式 适用版本 是否可变 推荐程度 场景建议
new HashSet<>(Arrays.asList()) Java 5+ ✅ 可变 ⭐⭐⭐⭐ 通用初始化,无依赖
双大括号初始化 Java 5+ ✅ 可变 ❌ 避免生产使用
Collections.singleton() Java 5+ ❌ 不可变 ⭐⭐⭐ 单元素场景
自定义 newHashSet() Java 5+ ✅ 可变 ⭐⭐⭐⭐⭐ 团队项目首选
Stream + Collectors Java 8+ ✅ 可变 ⭐⭐⭐⭐ 需预处理数据时
Guava Sets.newHashSet() Java 8+ ✅ 可变 ⭐⭐⭐⭐⭐ 有 Guava 依赖时
Guava ImmutableSet.of() Java 8+ ❌ 不可变 ⭐⭐⭐⭐⭐ 常量、配置项

🔚 最终建议:

  • **JDK9+**:优先使用 Set.of(...)(不可变)或 new HashSet<>(List.of(...))(可变)
  • 低版本 JDK:封装工具方法 or 引入 Guava
  • 避免双大括号,别为了少写两行代码埋下性能坑

所有示例代码均已上传至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-collections-set


原始标题:Initializing HashSet at the Time of Construction | Baeldung