作為一名 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核心技術深度解析!