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. 创建与初始化

dart 复制代码
// 使用 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. 添加元素

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

✅ 3. 删除元素

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

✅ 4. 查询元素

arduino 复制代码
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. 集合运算(交集、并集、差集)

ini 复制代码
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

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

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

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

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

// 遍历时顺序不变

✅ 4. 转换为 List 或数组

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

🧪 五、Set 的实际应用场景

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

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

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

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

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

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

ini 复制代码
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 实现自动排序的去重集合

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

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

javascript 复制代码
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核心技术深度解析!

相关推荐
小王不爱笑13233 分钟前
Java项目基本流程(三)
java·开发语言
David爱编程1 小时前
Java 三目运算符完全指南:写法、坑点与最佳实践
java·后端
遇见尚硅谷1 小时前
C语言:单链表学习
java·c语言·学习
学习编程的小羊1 小时前
Spring Boot 全局异常处理与日志监控实战
java·spring boot·后端
YA3332 小时前
java基础(六)jvm
java·开发语言
Moonbit3 小时前
MoonBit 作者寄语 2025 级清华深圳新生
前端·后端·程序员
前端的阶梯3 小时前
开发一个支持支付功能的微信小程序的注意事项,含泪送上
前端·后端·全栈
咕噜分发企业签名APP加固彭于晏3 小时前
腾讯元器的优点是什么
前端·后端
JavaArchJourney3 小时前
Java 集合框架
java
尘民10243 小时前
面试官笑了:线程start() 为什么不能再来一次?
java