如何用Map物件建立Set物件
Java中的Map和Set有不少相似之處。本文將分享一個把Map類轉化成Set類的小技巧。
或許你已經知道,HashSet其實是一個披著Set方法外衣的HashMap;同樣,TreeSet其實也是一個披著Set方法外衣的TreeMap。Map並不支援直接用迭代器進行遍歷,因此下面的這段程式碼編譯無法通過:
1
2
3
|
Map<String,
Double> salaries = new HashMap<>(); for ( double salary
: salaries) { //
does not compile } |
我們可以通過遍歷Map中的key集合、value集合和entry集合來實現Map的遍歷。由於Map中的value是可以重複出現的,因此values()方法返回的是一個Collection型別的集合。而Map中的key是不允許重複的,因此keySet()方法和entrySet()返回的都是Set型別的集合。
因此,我們可以採用下面的方法來遍歷Map:
1
2
3
|
Map<String,
Double> salaries = new HashMap<>(); for ( double salary
: salaries.values()) { } |
或者可以通過遍歷key來遍歷Map:
1
2
3
|
Map<String,
Double> salaries = new HashMap<>(); for (String
name : salaries.keySet()) { } |
當然,還可以通過遍歷entry來遍歷Map:
1
2
3
4
5
|
Map<String,
Double> salaries = new HashMap<>(); for (Map.Entry<String,
Double> entry : salaries.entrySet()) { String
name = entry.getKey(); double salary
= entry.getValue(); } |
我經常看到程式設計師這樣遍歷Map:先獲取keySet,然後對keys進行遍歷,並通過get()方法找到對應的value。
1
2
3
4
|
Map<String,
Double> salaries = new HashMap<>(); for (String
name : salaries.keySet()) { //
less efficient way to double salary
= salaries.get(name); //
iterate over entries } |
從直觀上看,採用遍歷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
|
import java.util.*; import java.util.concurrent.*; public class
ConcurrentSetTest { public static
void
main(String[] args) { Set<String>
names = Collections.newSetFromMap( new ConcurrentHashMap<String,
Boolean>() ); names.add( "Brian
Goetz" ); names.add( "Victor
Grazi" ); names.add( "Heinz
Kabutz" ); names.add( "Brian
Goetz" ); System.out.println( "names
= "
+ names); } } |
當然,newSetFromMap()方法只能返回標準Set介面型別的物件。如果你的Map類有著更豐富的介面(與標準Map<K, V>介面相比),你還是需要自行封裝實現對應的Set類。
希望讀者能從本文中有所收穫。如果你曾經為找不到ConcurrentHashSet而煩惱,現在你就可以自己建立一個了。
相關文章
- 【重溫基礎】11.Map和Set物件物件
- c++ unordered_map/set自定義物件的hashC++物件
- SCSS map物件CSS物件
- JavaScript Set物件JavaScript物件
- vue遍歷map物件Vue物件
- Java物件轉換成MapJava物件
- JavaScript中 Map 物件詳解JavaScript物件
- map物件拷貝問題物件
- JavaScript物件與建立物件的方式JavaScript物件
- JS_建立物件+呼叫物件方法JS物件
- 物件建立模式物件模式
- JS 建立物件JS物件
- JavaScript建立物件JavaScript物件
- js建立物件JS物件
- JS物件導向設計-建立物件JS物件
- javascript生成map物件的函式JavaScript物件函式
- 如何遍歷Map中的物件物件
- Java 中建立子類物件會建立父類物件麼?Java物件
- Java物件建立模式Java物件模式
- AJAX 建立 XMLHttpRequest物件XMLHTTP物件
- JS-建立物件JS物件
- ajax建立XMLHttpRequest物件XMLHTTP物件
- PHP 建立流式物件PHP物件
- 07物件的建立物件
- JavaScript物件導向—物件的建立和操作JavaScript物件
- 程式碼中使用DataView物件----建立DataView物件View物件
- js 中的json物件和mapJSON物件
- JavaScript 基礎(二) – 建立 function 物件的方法, String物件, Array物件JavaScriptFunction物件
- [寫作中...]Js物件導向(2): 建立物件JS物件
- 使用反射建立窗體物件時,物件為NULL反射物件Null
- js物件導向設計---建立物件的方式JS物件
- 使用反射-動態建立物件及呼叫物件方法反射物件
- js物件建立進階JS物件
- createObjectStore() 建立物件倉庫Object物件
- js 建立圖片物件JS物件
- javascript使用new建立物件JavaScript物件
- 物件的建立和分配物件
- 建立和銷燬物件物件