JavaRush /Java Blog /Random-TW /關於 Java 地圖的 9 大問題
Treefeed
等級 21

關於 Java 地圖的 9 大問題

在 Random-TW 群組發布
回想一下,Map是由一組鍵值對組成的結構化數據,每個鍵在單一 Map 中只能使用一次。本主題涵蓋在 Java 中使用Map及其實作類別的 9 個基本問題。為簡單起見,我將在範例中使用概括。因此,我將簡單地編寫Map,而不指定Map說明符。但你可以假設KV的值都是可比較的,這表示K擴展了Comparable,而V也擴展了Comparable關於 Java 地圖的 9 大問題 - 1

0. 將地圖轉換為列表

在Java中,Map介面提供了三種集合:鍵集、值集和鍵值集。所有這些都可以使用建構函數或方法轉換為列表addAll()。以下程式碼片段示範如何從 Map 建立ArrayList 。
// list of keys
List keyList = new ArrayList(Map.keySet());
//list of values
List valueList = new ArrayList(Map.valueSet());
//list key-value
List entryList = new ArrayList(Map.entrySet());

1.循環遍歷Map中的所有值

遍歷每個鍵值對是遍歷 Map 的最基本、最基本的過程。在 Java 中,每對都儲存在名為Map.Entry的 Map 欄位中。Map.entrySet()傳回一組鍵值,因此迭代 Map 的所有值的最有效方法是:
for(Entry entry: Map.entrySet()) {
  //get the key
  K key = entry.getKey();
  //get value
  V value = entry.getValue();
}
我們也可以使用Iterator,特別是在低於 JDK 1.5 的版本中
Iterator itr = Map.entrySet().iterator();
while(itr.hasNext()) {
  Entry entry = itr.next();
  //get the key
  K key = entry.getKey();
  //get value
  V value = entry.getValue();
}

2. 按鍵排序映射

按鍵組織映射是另一個常用的過程。第一種方法是將Map.Entry新增至清單中,並使用按值排序的比較器進行排序。
List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {

  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getKey().compareTo(e2.getKey());
  }
});
另一種方法:使用SortedMap,此外,它還按順序排列其鍵。但是,所有鍵都必須體現Comparable或被比較器接受。已實作的類別之一SortedMapTreeMap。它的建構函式接受一個比較器。下面的程式碼展示如何將普通的變成Map有序的。
SortedMap sortedMap = new TreeMap(new Comparator() {

  @Override
  public int compare(K k1, K k2) {
    return k1.compareTo(k2);
  }

});
sortedMap.putAll(Map);

3. 按值排序映射

在這種情況下,將地圖添加到列表中然後對其進行排序是可行的,但這次您需要使用Entry.getValue(). 下面的程式碼與之前幾乎相同。
List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {

  @Override
  public int compare(Entry e1, Entry e2) {
    return e1.getValue().compareTo(e2.getValue());
  }

});
在這種情況下我們仍然可以使用它SortedMap,但前提是值是唯一的。這種情況下,可以將鍵值對變成鍵值。該解決方案有嚴重的局限性,我不推薦。

4. 初始化靜態/不可變Map

當您希望 Map 保持不可變時,一個好方法是將其複製到不可變 Map 中。這種防禦性程式設計技術將幫助您創建一個不僅使用安全而且線程安全的 Map。要初始化靜態/不可變映射,我們可以使用初始化器static(見下文)。這段程式碼的問題在於,儘管將 Map 聲明為static final,但我們仍然可以在初始化後使用它,例如Test.Map.put(3,"three");。所以這並不是真正的不變性。要使用靜態初始化器建立不可變的 Map,我們需要一個超級匿名類,我們將在最後的初始化步驟中將其新增到不可變的 Map 中。請看程式碼的第二部分。當運行時會拋出UnsupportedOperationExceptionTest.Map.put(3,"three");
public class Test {

  private static final Map Map;
  static {
    Map = new HashMap();
    Map.put(1, "one");
    Map.put(2, "two");
  }
}
public class Test {

  private static final Map Map;
  static {
    Map aMap = new HashMap();
    aMap.put(1, "one");
    aMap.put(2, "two");
    Map = Collections.unmodifiableMap(aMap);
  }
}
Guava 函式庫也支援各種方式來初始化靜態和不可變集合。要了解有關 Guava 不可變集合實用程式的優勢的更多信息,請參閱Guava How-to 中的不可變集合部分

5.HashMap、TreeMap、Hashtable的差別

Java 中Map介面的三個主要實作: HashMapTreeMapHashtable。主要區別如下:
  • 通過順序HashMap和HashTable不保證Map的順序;特別是,他們不保證訂單隨著時間的推移保持不變。但TreeMap它會按照鍵的“自然順序”或透過比較器對所有值進行排序。
  • 有效的鍵值對。 HashMap允許您有一個空鍵和一個空值。HashTable不允許空鍵或空值。如果TreeMap使用自然順序或比較器不允許空鍵,則會拋出例外。
  • 同步。僅HashTable同步,其餘不同步。但是,「如果不需要線程安全的實現,建議使用HashMapHashTable
更詳細的比較
.                       | HashMap | HashTable | TreeMap
-------------------------------------------------------

Упорядочивание          |нет      |нет        | да
null в ключ-meaning    | да-да   | нет-нет   | нет-да
синхронизировано        | нет     | да        | нет
производительность      | O(1)    | O(1)      | O(log n)
воплощение              | корзины | корзины   | красно-чёрное дерево
閱讀有關HashMap 與關係的更多資訊。樹狀圖對比 哈希表對比 LinkedHashMap

6. 具有反向搜尋/檢視功能的地圖

有時,我們需要一組鍵-鍵對,這意味著值與鍵一樣唯一(一對一模式)。這種一致性允許您在地圖上建立“反向視圖/搜尋”。也就是說,我們可以透過它的值找到一個鍵。這種資料結構稱為雙向 Map,不幸的是 JDK 不支援它。Apache Common Collections 和 Guava 都提供雙向 Map 實現,分別稱為 BidiMap 和 BiMap。兩者都引入了強制鍵和值之間 1:1 映射的約束。

7.Map的淺拷貝

幾乎所有(如果不是全部)Java 中的 Map 都包含另一個 Map 的複製建構子。但複製過程不同步。這意味著當一個線程複製 Map 時,另一個線程可以更改其結構。為了防止複製突然不同步,在這種情況下應該使用其中之一Collections.synchronizedMap()
Map copiedMap = Collections.synchronizedMap(Map);
另一種有趣的淺複製方法是使用clone(). 但即使是 Java 集合框架的創建者 Joshua Bloch 也不建議這樣做。在「複製建構函數與複製」辯論中,他採取的立場是: 引用:「我經常在具體類別中包含公共克隆方法,因為人們期望它們在那裡......克隆被破壞是一種恥辱,但它發生了……克隆是一個弱點,我認為人們應該警惕它的局限性。” 因此,我甚至不向您展示如何使用clone()複製 Map 的 方法

8. 建立一個空地圖

如果Map不可變,請使用:
Map = Collections.emptyMap();
或者,使用任何其他實施例。例如:
Map = new HashMap();
結尾
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION