Java中的Map和Set有很多類似之處。本文將分享一個把Map類轉化成Set類的小技巧。java
或許你已經知道,HashSet實際上是一個披着Set方法外衣的HashMap;一樣,TreeSet其實也是一個披着Set方法外衣的TreeMap。Map並不支持直接用迭代器進行遍歷,所以下面的這段代碼編譯沒法經過:程序員
1算法 2sql 3安全 |
|
咱們能夠經過遍歷Map中的key集合、value集合和entry集合來實現Map的遍歷。因爲Map中的value是能夠重複出現的,所以values()方法返回的是一個Collection類型的集合。而Map中的key是不容許重複的,所以keySet()方法和entrySet()返回的都是Set類型的集合。jsp
所以,咱們能夠採用下面的方法來遍歷Map:分佈式
1 2 3 |
|
或者能夠經過遍歷key來遍歷Map:
1 2 3 |
|
固然,還能夠經過遍歷entry來遍歷Map:
1 2 3 4 5 |
|
我常常看到程序員這樣遍歷Map:先獲取keySet,而後對keys進行遍歷,並經過get()方法找到對應的value。
1 2 3 4 |
|
從直觀上看,採用遍歷entry的方式遍歷Map會更加高效一些,這種遍歷方式的時間複雜度是O(n)。然而,若是HashMap中的元素分佈均勻,調用get()方法查找元素的時間複雜度將是O(1),那麼這兩種方法遍歷HashMap的時間複雜度是同樣的,都是O(n)。這兩種遍歷方式雖然有所不一樣,但時間複雜度都是線性的。但這個結論並不適用於其它類型的Map,特別是TreeMap。TreeMap的平均查找效率是O(log n),所以經過keySet遍歷TreeMap的時間複雜度是O(n x log n)。
java.util包中有不少Map類,其中一些Map類有着對應類型的Set類實現,例如TreeMap和HashMap。這些Set類都是基於對應的Map類實現的,所以它們和對應的Map類保持相同的算法複雜度以及併發特性。
本文的重點來了。我在完成併發專修課程中的某道練習題時,須要一個快速高效而且線程安全的HashSet。起初,我直接把ConcurrentHashMap看成Set用,把要插入Set的元素以Key的形式插入Map,Key所對應的Value則是一個無心義的默認值。後來我發現,Java 6中的java.util.Collections類提供了一個newSetFromMap()方法,該方法可以基於指定的Map對象建立一個新的Set對象。在建立這個Map<K, V>對象時,K的數據類型必須與你想要建立的Set中元素的數據類型一致;而V必須是Boolean類型的,這是由於value字段用於標記該元素是否存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
固然,newSetFromMap()方法只能返回標準Set接口類型的對象。若是你的Map類有着更豐富的接口(與標準Map<K, V>接口相比),你仍是須要自行封裝實現對應的Set類。
但願讀者能從本文中有所收穫。若是你曾經爲找不到ConcurrentHashSet而煩惱,如今你就能夠本身建立一個了。
歡迎工做一到五年的Java工程師朋友們加入Java架構開發:855801563
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代