Java Set 集合详解:从基础语法到实战应用,彻底掌握去重与唯一性集合

作为一名 Java 开发工程师 ,你一定在实际开发中遇到过需要去重、唯一性校验、快速查找 等场景。这时候,Set 集合 就成为你不可或缺的工具。

本文将带你全面掌握:

  • Set 接口的定义与核心方法
  • 常见实现类(如 HashSetTreeSetLinkedHashSet
  • Set 的去重原理(equals()hashCode()
  • Set 的遍历、增删查改、集合运算(交集、并集、差集)
  • Set 在实际业务中的应用场景
  • 线程安全与并发使用的最佳实践

并通过丰富的代码示例和真实项目场景讲解,帮助你写出更高效、结构更清晰的 Java 集合代码。


🧱 一、什么是 Set 集合?

Set 是 Java 集合框架中 Collection 接口的子接口之一,它表示一个不包含重复元素的集合。

Set 的核心特性:

特性 描述
不允许重复 元素不能重复(通过 equals()hashCode() 判断)
无序 默认不保证插入顺序(LinkedHashSet 除外)
无索引访问 不能通过索引获取元素
支持泛型 推荐使用泛型来保证类型安全
适用于唯一性操作 如去重、集合运算、快速查找等

🔍 二、Set 的常见实现类

实现类 特点 适用场景
HashSet 基于哈希表实现,无序,查找快 默认唯一性集合
LinkedHashSet 哈希表 + 双向链表,保持插入顺序 保持顺序的唯一集合
TreeSet 基于红黑树实现,自动排序 需要排序的唯一集合
ConcurrentSkipListSet 线程安全,基于跳表实现 高并发下排序集合

🧠 三、Set 的基本操作

✅ 1. 创建与初始化

复制代码
// 使用 HashSet 初始化
Set<String> set = new HashSet<>();

// 静态初始化
Set<String> set2 = new HashSet<>(Arrays.asList("Java", "Python", "C++"));

// 不可变集合(Java 9+)
Set<String> set3 = Set.of("A", "B", "C");

✅ 2. 添加元素

复制代码
set.add("Java");            // 添加元素
set.add("Java");            // 不会重复添加
set.addAll(Arrays.asList("Python", "JavaScript")); // 添加集合

✅ 3. 删除元素

复制代码
set.remove("Java");         // 删除指定元素
set.clear();                // 清空集合

✅ 4. 查询元素

复制代码
boolean contains = set.contains("Java"); // 是否包含某个元素
int size = set.size();      // 获取集合大小
boolean isEmpty = set.isEmpty(); // 是否为空

✅ 5. 遍历方式对比

遍历方式 示例 特点
增强 for 循环 for (String s : set) 简洁易读
Iterator 迭代器 Iterator<String> it = set.iterator(); while (it.hasNext()) 支持在遍历中删除
Stream 流式处理 set.stream().forEach(System.out::println) 支持过滤、映射、排序等操作

🔁 四、Set 的高级操作

✅ 1. 集合运算(交集、并集、差集)

复制代码
Set<String> set1 = new HashSet<>(Arrays.asList("A", "B", "C"));
Set<String> set2 = new HashSet<>(Arrays.asList("B", "C", "D"));

// 并集
Set<String> union = new HashSet<>(set1);
union.addAll(set2);

// 交集
Set<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2);

// 差集
Set<String> difference = new HashSet<>(set1);
difference.removeAll(set2);

✅ 2. 排序(使用 TreeSet

复制代码
Set<String> sortedSet = new TreeSet<>();
sortedSet.addAll(Arrays.asList("Banana", "Apple", "Orange"));

// 输出顺序:Apple, Banana, Orange

✅ 3. 保持插入顺序(使用 LinkedHashSet

复制代码
Set<String> orderedSet = new LinkedHashSet<>();
orderedSet.add("First");
orderedSet.add("Second");
orderedSet.add("Third");

// 遍历时顺序不变

✅ 4. 转换为 List 或数组

复制代码
List<String> list = new ArrayList<>(set);
String[] array = set.toArray(new String[0]);

🧪 五、Set 的实际应用场景

场景1:去重处理(最常见用途)

复制代码
List<String> duplicates = Arrays.asList("a", "b", "a", "c");
Set<String> unique = new HashSet<>(duplicates); // {"a", "b", "c"}

场景2:权限校验(判断是否包含权限)

复制代码
Set<String> permissions = new HashSet<>(Arrays.asList("read", "write", "admin"));

if (permissions.contains("delete")) {
    // 执行删除操作
}

场景3:数据同步与差异检测(如数据库对比)

复制代码
Set<String> dbUsers = getFromDB(); // 数据库中的用户
Set<String> fileUsers = getFromFile(); // 文件中的用户

Set<String> toAdd = new HashSet<>(fileUsers);
toAdd.removeAll(dbUsers); // 需要新增的用户

Set<String> toRemove = new HashSet<>(dbUsers);
toRemove.removeAll(fileUsers); // 需要删除的用户

场景4:使用 TreeSet 实现自动排序的去重集合

复制代码
Set<Integer> numbers = new TreeSet<>();
numbers.addAll(Arrays.asList(5, 3, 8, 1, 3));
// 输出顺序:1, 3, 5, 8

场景5:线程安全的 Set(多线程环境)

复制代码
Set<String> safeSet = Collections.synchronizedSet(new HashSet<>());

// 或使用并发集合
Set<String> concurrentSet = new CopyOnWriteArraySet<>();

🚫 六、常见误区与注意事项

误区 正确做法
忘记重写 equals()hashCode() 自定义类作为 Set 元素时必须重写
使用 == 比较字符串 使用 equals()Objects.equals()
在遍历中直接删除元素 使用 Iterator.remove()
忘记初始化 Set 就使用 new HashSet<>()
忽略线程安全问题 多线程使用 CopyOnWriteArraySet 或同步包装
错误使用 Set.of() 修改列表 Set.of(...) 是不可变集合,修改会抛出异常

🧱 七、SetList 的区别对比

对比项 Set List
是否允许重复 不允许 允许
是否有序 不保证顺序(LinkedHashSet 除外) 有序
是否支持索引访问 不支持 支持
是否适合去重 非常适合 不适合
常用实现类 HashSet, TreeSet, LinkedHashSet ArrayList, LinkedList

📊 八、总结:Java Set 核心知识点一览表

内容 说明
接口定义 Set<E>
常用实现类 HashSet, TreeSet, LinkedHashSet, CopyOnWriteArraySet
核心方法 add、remove、contains、size、isEmpty、iterator
遍历方式 增强 for、Iterator、Stream
高级操作 集合运算、排序、保持顺序、去重
线程安全 Collections.synchronizedSet()CopyOnWriteArraySet
应用场景 去重、权限控制、数据同步、集合运算

📎 九、附录:Set 常用技巧速查表

技巧 示例
创建只读集合 Collections.unmodifiableSet(set)
同步集合 Collections.synchronizedSet(new HashSet<>())
集合转数组 set.toArray(new String[0])
判断是否为空 set.isEmpty()
获取最大最小值 Collections.max(set) / Collections.min(set)(需为 SortedSet
使用 Stream 过滤 set.stream().filter(s -> s.startsWith("A")).toList()
使用 Stream 转换 set.stream().map(String::toUpperCase).toList()
使用 Stream 收集到 Set list.stream().collect(Collectors.toSet())
判断是否是子集 set1.containsAll(set2)
集合交集 set1.retainAll(set2)

如果你正在准备一篇面向初学者的技术博客,或者希望系统回顾 Java 基础知识,这篇文章将为你提供完整的知识体系和实用的编程技巧。

欢迎点赞、收藏、转发,也欢迎留言交流你在实际项目中遇到的 Set 集合相关问题。我们下期再见 👋

📌 关注我,获取更多Java核心技术深度解析!

相关推荐
Mr_Xuhhh4 分钟前
QT窗口(4)-浮动窗口
android·开发语言·网络·数据库·c++·qt
冲!!6 分钟前
前端获取当前日期并格式化(JS)
开发语言·前端·javascript
ansurfen10 分钟前
耗时一周,我的编程语言 Hulo 新增 Bash 转译和包管理工具
后端·编程语言
库森学长19 分钟前
索引失效的场景有哪些?
后端·mysql·面试
oioihoii20 分钟前
Visual Studio C++编译器优化等级详解:配置、原理与编码实践
java·c++·visual studio
没有羊的王K21 分钟前
SSM框架——Day4
java·开发语言
24kHT23 分钟前
2.3 前端-ts的接口以及自定义类型
java·开发语言·前端
我命由我1234530 分钟前
VSCode - VSCode 快速跳转标签页
开发语言·前端·ide·vscode·编辑器·html·js
Mr_Xuhhh34 分钟前
QT窗口(3)-状态栏
java·c语言·开发语言·数据库·c++·qt·算法
SHUIPING_YANG36 分钟前
PHP 8.0 升级到 PHP 8.1
开发语言·php