Set接口
Set是一個(gè)不能包含重復(fù)元素的Collection,它模擬了數(shù)學(xué)集抽象,Set接口僅包含從Collection繼承的方法,并添加禁止重復(fù)元素的限制,Set還為equals和hashCode操作的行為添加了一個(gè)更強(qiáng)的契約,允許Set實(shí)例有意義地進(jìn)行比較,即使它們的實(shí)現(xiàn)類型不同,如果兩個(gè)Set實(shí)例包含相同的元素,則它們是相等的。
Java平臺(tái)包含三個(gè)通用的Set實(shí)現(xiàn):HashSet、TreeSet和LinkedHashSet。將其元素存儲(chǔ)在哈希表中的HashSet是性能最佳的實(shí)現(xiàn),但它不能保證迭代的順序。TreeSet將其元素存儲(chǔ)在紅黑樹中,根據(jù)元素的值對(duì)其元素進(jìn)行排序,它比HashSet慢得多。LinkedHashSet實(shí)現(xiàn)為哈希表,其中有一個(gè)鏈表,根據(jù)它們插入集合的順序(插入順序)對(duì)其元素進(jìn)行排序,LinkedHashSet讓它的客戶端避免了HashSet提供的未指定的、通常混亂的排序,但代價(jià)只稍微高一點(diǎn)。
這是一個(gè)簡(jiǎn)單但有用的Set語(yǔ)法,假設(shè)你有一個(gè)Collection,c,并且你想要?jiǎng)?chuàng)建另一個(gè)包含相同元素的Collection,但會(huì)刪除所有重復(fù)項(xiàng),下面的一行代碼就可以解決這個(gè)問題。
CollectionnoDups = new HashSet (c);
它的工作原理是創(chuàng)建一個(gè)Set(根據(jù)定義,它不能包含重復(fù)項(xiàng)),初始化包含c中的所有元素,它使用Collection接口部分中描述的標(biāo)準(zhǔn)轉(zhuǎn)換構(gòu)造函數(shù)。
或者,如果使用JDK 8或更高版本,你可以使用聚合操作輕松收集到Set:
c.stream() .collect(Collectors.toSet()); // no duplicates
這是一個(gè)稍長(zhǎng)的示例,它將名稱Collection累積到TreeSet中:
Setset = people.stream() .map(Person::getName) .collect(Collectors.toCollection(TreeSet::new));
以下是第一個(gè)語(yǔ)法的次要變體,它在刪除重復(fù)元素時(shí)保留了原始集合的順序:
CollectionnoDups = new LinkedHashSet (c);
以下是封裝前面的語(yǔ)法的泛型方法,返回與傳遞的相同的泛型類型的Set。
public staticSet接口基礎(chǔ)操作Set removeDups(Collection c) { return new LinkedHashSet (c); }
size操作返回Set中的元素?cái)?shù)(其基數(shù)),isEmpty方法完全符合你的想法,add方法將指定的元素添加到Set(如果它尚不存在)并返回一個(gè)布爾值,指示是否添加了元素。類似地,remove方法從Set中刪除指定的元素(如果存在)并返回一個(gè)布爾值,指示元素是否存在,iterator方法在Set上返回Iterator。
以下程序打印出其參數(shù)列表中的所有不同單詞,提供了該程序的兩個(gè)版本,第一個(gè)使用JDK 8聚合操作,第二個(gè)使用for-each構(gòu)造。
使用JDK 8聚合操作:
import java.util.*; import java.util.stream.*; public class FindDups { public static void main(String[] args) { SetdistinctWords = Arrays.asList(args).stream() .collect(Collectors.toSet()); System.out.println(distinctWords.size()+ " distinct words: " + distinctWords); } }
使用for-each構(gòu)造:
import java.util.*; public class FindDups { public static void main(String[] args) { Sets = new HashSet (); for (String a : args) s.add(a); System.out.println(s.size() + " distinct words: " + s); } }
現(xiàn)在運(yùn)行該程序的任一版本。
java FindDups i came i saw i left
生成以下輸出:
4 distinct words: [left, came, saw, i]
請(qǐng)注意,代碼始終引用Collection通過其接口類型(Set)而不是其實(shí)現(xiàn)類型,這是一個(gè)強(qiáng)烈推薦的編程實(shí)踐,因?yàn)樗鼓憧梢造`活地僅通過更改構(gòu)造函數(shù)來(lái)更改實(shí)現(xiàn)。如果用于存儲(chǔ)集合的變量或用于傳遞它的參數(shù)中的任何一個(gè)被聲明為Collection的實(shí)現(xiàn)類型而不是其接口類型,必須更改所有這些變量和參數(shù)才能更改其實(shí)現(xiàn)類型。
此外,無(wú)法保證生成的程序能夠正常運(yùn)行,如果程序使用原始實(shí)現(xiàn)類型中存在但未在新實(shí)現(xiàn)類型中存在的任何非標(biāo)準(zhǔn)操作,則程序?qū)⑹?,僅通過其接口引用集合可防止你使用任何非標(biāo)準(zhǔn)操作。
前面示例中Set的實(shí)現(xiàn)類型是HashSet,它不保證Set中元素的順序,如果你希望程序按字母順序打印單詞列表,只需將Set的實(shí)現(xiàn)類型從HashSet更改為TreeSet,進(jìn)行這個(gè)簡(jiǎn)單的單行更改會(huì)導(dǎo)致前一個(gè)示例中的命令行生成以下輸出。
java FindDups i came i saw i left 4 distinct words: [came, i, left, saw]Set接口批量操作
批量操作特別適合于Set,應(yīng)用時(shí),它們執(zhí)行標(biāo)準(zhǔn)的集代數(shù)運(yùn)算,假設(shè)s1和s2是Set,批量操作是這樣做的:
s1.containsAll(s2) — 如果s2是s1的子集,則返回true(如果set s1包含s2中的所有元素,則s2是s1的子集)。
s1.addAll(s2) — 將s1轉(zhuǎn)換為s1和s2的并集(兩個(gè)集合的并集是包含任一集合中包含的所有元素的集合)。
s1.retainAll(s2) — 將s1轉(zhuǎn)換為s1和s2的交集(兩個(gè)集合的交集是僅包含兩個(gè)集合共有的元素的集合)。
s1.removeAll(s2) — 將s1轉(zhuǎn)換為s1和s2的(非對(duì)稱)差集(例如,s1減s2的差集就是包含s1中所有元素但不包含s2中的所有元素的集)。
若要非破壞性地計(jì)算兩個(gè)集合的并集、交集或差集(不修改任何一個(gè)集合),調(diào)用者必須在調(diào)用適當(dāng)?shù)呐坎僮髦皬?fù)制一個(gè)集合,以下是由此產(chǎn)生的語(yǔ)法。
Setunion = new HashSet (s1); union.addAll(s2); Set intersection = new HashSet (s1); intersection.retainAll(s2); Set difference = new HashSet (s1); difference.removeAll(s2);
前面的語(yǔ)法中的結(jié)果集的實(shí)現(xiàn)類型是HashSet,如前所述,它是Java平臺(tái)中最好的全能Set實(shí)現(xiàn),但是,任何通用的Set實(shí)現(xiàn)都可以替代。
讓我們重溫一下FindDups程序,假設(shè)你想知道參數(shù)列表中的哪些單詞只出現(xiàn)一次,哪些單詞出現(xiàn)多次,但你不希望重復(fù)打印出任何重復(fù)項(xiàng),這種效果可以通過生成兩個(gè)集合來(lái)實(shí)現(xiàn) — 一個(gè)集合包含參數(shù)列表中的每個(gè)單詞,另一個(gè)集合僅包含重復(fù)項(xiàng)。僅出現(xiàn)一次的單詞是這兩組的差集,我們知道如何計(jì)算,以下是生成的程序的樣子。
import java.util.*; public class FindDups2 { public static void main(String[] args) { Setuniques = new HashSet (); Set dups = new HashSet (); for (String a : args) if (!uniques.add(a)) dups.add(a); // Destructive set-difference uniques.removeAll(dups); System.out.println("Unique words: " + uniques); System.out.println("Duplicate words: " + dups); } }
當(dāng)使用前面使用的相同參數(shù)列表運(yùn)行時(shí)(i came i saw i left),程序產(chǎn)生以下輸出。
Unique words: [left, saw, came] Duplicate words: [i]
不太常見的集代數(shù)運(yùn)算是對(duì)稱差集 — 包含在兩個(gè)指定集合中但不同時(shí)包含在兩個(gè)集合中的元素的集合,以下代碼非破壞性地計(jì)算兩個(gè)集合的對(duì)稱差集。
SetSet接口數(shù)組操作symmetricDiff = new HashSet (s1); symmetricDiff.addAll(s2); Set tmp = new HashSet (s1); tmp.retainAll(s2); symmetricDiff.removeAll(tmp);
除了對(duì)其他任何Collection執(zhí)行的操作之外,數(shù)組操作不會(huì)對(duì)Set執(zhí)行任何特殊操作,Collection接口部分介紹了這些操作。
上一篇:Collection接口 下一篇:List接口文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/73096.html
集合接口 核心集合接口封裝了不同類型的集合,如下圖所示,這些接口允許獨(dú)立于其表示的細(xì)節(jié)來(lái)操縱集合,核心集合接口是Java集合框架的基礎(chǔ),如下圖所示,核心集合接口形成層次結(jié)構(gòu)。 showImg(https://segmentfault.com/img/bVbntJW?w=402&h=146); Set是一種特殊的Collection,SortedSet是一種特殊的Set,依此類推,另請(qǐng)注意,層次結(jié)構(gòu)...
List接口 List是一個(gè)有序的Collection(有時(shí)稱為序列),列表可能包含重復(fù)元素,除了從Collection繼承的操作之外,List接口還包括以下操作: 位置訪問 — 根據(jù)列表中的數(shù)字位置操縱元素,這包括get、set、add、addAll和remove等方法。 搜索 — 搜索列表中的指定對(duì)象并返回其數(shù)字位置,搜索方法包括indexOf和lastIndexOf。 迭代 — 擴(kuò)展Ite...
SortedSet接口 SortedSet是一個(gè)Set,它按升序維護(hù)其元素,根據(jù)元素的自然順序或根據(jù)SortedSet創(chuàng)建時(shí)提供的Comparator進(jìn)行排序,除了常規(guī)的Set操作外,SortedSet接口還提供以下操作: 范圍視圖 — 允許對(duì)已排序集進(jìn)行任意范圍操作。 端點(diǎn) — 返回有序集合中的第一個(gè)或最后一個(gè)元素。 比較器訪問 — 返回用于對(duì)集合進(jìn)行排序的Comparator(如果有)。 ...
Map接口 Map是將鍵映射到值的對(duì)象,map不能包含重復(fù)的鍵:每個(gè)鍵最多可以映射一個(gè)值,它模擬數(shù)學(xué)函數(shù)抽象。Map接口包括基本操作的方法(如put、get、remove、containsKey、containsValue、size和empty),批量操作(如putAll和clear)和集合視圖(如keySet、entrySet和values)。 Java平臺(tái)包含三個(gè)通用Map實(shí)現(xiàn):HashMap...
泛型類型 泛型類型是通過類型參數(shù)化的泛型類或接口,修改以下Box類以演示此概念。 一個(gè)簡(jiǎn)單的Box類 首先檢查一個(gè)對(duì)任何類型的對(duì)象進(jìn)行操作的非泛型Box類,它只需要提供兩個(gè)方法:set,它將一個(gè)對(duì)象添加到box中,get,它將檢索它: public class Box { private Object object; public void set(Object object) ...
閱讀 803·2021-10-09 09:58
閱讀 668·2021-08-27 16:24
閱讀 1753·2019-08-30 14:15
閱讀 2409·2019-08-30 11:04
閱讀 2120·2019-08-29 18:43
閱讀 2188·2019-08-29 15:20
閱讀 2749·2019-08-26 12:20
閱讀 1651·2019-08-26 11:44