作为一名 Java 开发工程师,你一定在实际开发中遇到过需要去重、唯一性校验、快速查找等场景。这时候,Set
集合 就成为你不可或缺的工具。
本文将带你全面掌握:
Set
接口的定义与核心方法- 常见实现类(如
HashSet
、TreeSet
、LinkedHashSet
) 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(...) 是不可变集合,修改会抛出异常 |
🧱 七、Set
与 List
的区别对比
对比项 | 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核心技术深度解析!