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核心技术深度解析!

相关推荐
努力的小郑3 分钟前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
赫瑞22 分钟前
数据结构中的排列组合 —— Java实现
java·开发语言·数据结构
Victor3561 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3561 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁1 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp1 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
周末也要写八哥2 小时前
多进程和多线程的特点和区别
java·开发语言·jvm
惜茶2 小时前
vue+SpringBoot(前后端交互)
java·vue.js·spring boot
宁瑶琴3 小时前
COBOL语言的云计算
开发语言·后端·golang
杰克尼3 小时前
springCloud_day07(MQ高级)
java·spring·spring cloud