Java中Set特性與常用方法示例詳解
Java 中的 Set 是 Collection 接口的子接口,不允許存儲(chǔ)重復(fù)元素,且不保證順序(除特定實(shí)現(xiàn)外)。以下是核心特性和常用方法:
一、核心特性
| 特性 | 說(shuō)明 |
|---|---|
| 唯一性 | 不允許重復(fù)元素(基于 equals() 和 hashCode() 判斷) |
| 無(wú)序性 | 不保證插入順序(LinkedHashSet 和 TreeSet 除外) |
| 允許 null | 通常允許一個(gè) null(TreeSet 不允許) |
| 無(wú)索引 | 沒(méi)有 get(index) 方法,不能通過(guò)索引訪問(wèn) |
二、主要實(shí)現(xiàn)類對(duì)比
| 實(shí)現(xiàn)類 | 底層結(jié)構(gòu) | 有序性 | 線程安全 | 適用場(chǎng)景 |
|---|---|---|---|---|
| HashSet | 哈希表(HashMap) | 無(wú)序 | 否 | 快速查找、去重 |
| LinkedHashSet | 哈希表 + 雙向鏈表 | 插入順序 | 否 | 需保持插入順序 |
| TreeSet | 紅黑樹(shù)(TreeMap) | 自然/定制排序 | 否 | 需排序范圍查詢 |
| CopyOnWriteArraySet | 數(shù)組 | 無(wú)序 | 是 | 讀多寫(xiě)少并發(fā)場(chǎng)景 |
三、常用方法
1. 基礎(chǔ)操作(繼承自 Collection)
Set<String> set = new HashSet<>();
// 增
set.add("A"); // 添加成功返回 true,已存在返回 false
set.addAll(anotherSet); // 批量添加
// 刪
set.remove("A"); // 刪除指定元素
set.removeIf(s -> s.startsWith("A")); // 按條件刪除(Java 8+)
set.clear(); // 清空所有元素
// 查
set.contains("A"); // 判斷是否包含,O(1) 時(shí)間
set.isEmpty(); // 是否為空
set.size(); // 元素個(gè)數(shù)
// 遍歷
for (String s : set) { }
set.forEach(System.out::println);
Iterator<String> it = set.iterator();2. 批量操作(集合運(yùn)算)
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3)); Set<Integer> set2 = new HashSet<>(Arrays.asList(2, 3, 4)); // 交集 set1.retainAll(set2); // set1 變?yōu)?[2, 3] // 并集 set1.addAll(set2); // set1 變?yōu)?[1, 2, 3, 4] // 差集 set1.removeAll(set2); // set1 中去掉 set2 的元素 // 包含判斷 set1.containsAll(set2); // set1 是否包含 set2 所有元素
四、各實(shí)現(xiàn)類特性詳解
1. HashSet(最常用)
Set<String> set = new HashSet<>(); // 初始容量16,負(fù)載因子0.75 // 自定義初始容量(減少擴(kuò)容次數(shù)) Set<String> set = new HashSet<>(1000); // 去重原理:先比較 hashCode,再比較 equals
?? 注意:元素必須正確重寫(xiě) hashCode() 和 equals()
// 錯(cuò)誤示例:自定義類未重寫(xiě)導(dǎo)致去重失敗
class Person {
String name;
// 未重寫(xiě) hashCode/equals,默認(rèn)按地址比較
}
// 正確做法
class Person {
String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}2. LinkedHashSet(保持插入順序)
Set<String> set = new LinkedHashSet<>();
set.add("B");
set.add("A");
set.add("C");
// 遍歷順序:B, A, C(與插入順序一致)3. TreeSet(自動(dòng)排序)
// 自然排序(元素實(shí)現(xiàn) Comparable) Set<Integer> set = new TreeSet<>(); set.add(3); set.add(1); set.add(2); // 遍歷結(jié)果:1, 2, 3 // 定制排序(Comparator) Set<String> set = new TreeSet<>(Comparator.reverseOrder()); Set<Person> set = new TreeSet<>(Comparator.comparing(Person::getAge)); // 特有方法(SortedSet 接口) TreeSet<Integer> ts = new TreeSet<>(); ts.first(); // 最小元素 ts.last(); // 最大元素 ts.headSet(5); // 小于5的子集 ts.tailSet(5); // 大于等于5的子集 ts.subSet(2, 5); // [2, 5) 范圍的子集
五、Stream API 操作(Java 8+)
List<Integer> list = Arrays.asList(1, 2, 2, 3, 3, 3);
// List 轉(zhuǎn) Set 去重
Set<Integer> set = list.stream().collect(Collectors.toSet());
// 過(guò)濾 + 收集
Set<String> result = set.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toCollection(LinkedHashSet::new));
// 找最大/最小
Optional<Integer> max = set.stream().max(Integer::compareTo);六、線程安全方案
// 1. Collections 包裝(讀寫(xiě)都加鎖,性能差) Set<String> syncSet = Collections.synchronizedSet(new HashSet<>()); // 2. CopyOnWriteArraySet(讀多寫(xiě)少推薦) Set<String> cowSet = new CopyOnWriteArraySet<>(); // 寫(xiě)操作復(fù)制整個(gè)數(shù)組,讀操作無(wú)鎖 // 3. ConcurrentHashMap 的 KeySet(Java 8+) Set<String> concurrentSet = ConcurrentHashMap.newKeySet();
七、常見(jiàn)面試題
| 問(wèn)題 | 答案 |
|---|---|
HashSet 如何檢查重復(fù)? | 先比較 hashCode,相同再比較 equals |
為什么重寫(xiě) equals 必須重寫(xiě) hashCode? | 保證相等對(duì)象有相同哈希值,否則 HashSet 會(huì)去重失敗 |
TreeSet 插入 null 報(bào)錯(cuò)? | 因?yàn)樾枰容^排序,null 無(wú)法比較 |
HashSet 和 HashMap 關(guān)系? | HashSet 底層是 HashMap,元素作為 Key,Value 是固定對(duì)象 |
到此這篇關(guān)于Java中Set特性與常用方法的文章就介紹到這了,更多相關(guān)java set方法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java.net.MalformedURLException異常的解決方法
下面小編就為大家?guī)?lái)一篇java.net.MalformedURLException異常的解決方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
Reactor 多任務(wù)并發(fā)執(zhí)行且結(jié)果按順序返回第一個(gè)
這篇文章主要介紹了Reactor 多任務(wù)并發(fā)執(zhí)行且結(jié)果按順序返回第一個(gè),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下2022-09-09
多模字符串匹配算法原理及Java實(shí)現(xiàn)代碼
這篇文章主要介紹了多模字符串匹配算法原理及Java實(shí)現(xiàn)代碼,涉及算法背景,原理,構(gòu)建過(guò)程簡(jiǎn)單介紹幾Java代碼實(shí)現(xiàn)等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11
java設(shè)計(jì)模式-單例模式實(shí)現(xiàn)方法詳解
單例模式,屬于創(chuàng)建類型的一種常用的軟件設(shè)計(jì)模式。通過(guò)單例模式的方法創(chuàng)建的類在當(dāng)前進(jìn)程中只有一個(gè)實(shí)例(根據(jù)需要,也有可能一個(gè)線程中屬于單例2021-07-07

