Java中實現不可變Map

banq發表於2018-12-08

有時最好不允許修改  java.util.Map, 例如跨執行緒共享只讀資料。為此,我們可以使用Unmodifiable Map或Immutable Map。
在這個快速教程中,我們將看到它們之間的區別。然後,我們將介紹可以建立不可變Map的各種方法。

不可修改與不可變
Unmodifiable Map其實是一個可以修改的map的包裝器,不允許直接修改它。

Map<String, String> mutableMap = new HashMap<>();
mutableMap.put("USA", "North America");

Map<String, String> unmodifiableMap = Collections.unmodifiableMap(mutableMap);
assertThrows(UnsupportedOperationException.class,
  () -> unmodifiableMap.put("Canada", "North America"));


但是包裝器裡面底層的可變Map仍然可以改變,修改也反映在不可修改的Map中:

mutableMap.remove("USA");
assertFalse(unmodifiableMap.containsKey("USA"));
        
mutableMap.put("Mexico", "North America");
assertTrue(unmodifiableMap.containsKey("Mexico"));


另一方面,不可變Map包含其自己的私有資料,是不允許對其進行修改。因此,一旦建立了不可變Map的例項,資料就不會以任何方式改變。



Guava不變Map

Guava提供了每個java.util的不可變版本。使用  ImmutableMap 對映 。每當我們嘗試修改它時,它都會丟擲  UnsupportedOperationException。
由於它包含自己的私有資料,因此在更改原始地圖時,此資料不會更改。

我們現在將討論建立ImmutableMap例項的各種方法  。
1. 使用copyOf()方法:
首先,讓我們使用ImmutableMap.copyOf()  方法,該方法返回原始Map中所有條目的副本:

ImmutableMap<String, String> immutableMap = ImmutableMap.copyOf(mutableMap);
assertTrue(immutableMap.containsKey("USA"));


它不能直接修改,但是可以改變其內部可變的Map:

assertThrows(UnsupportedOperationException.class,
  () -> immutableMap.put("Canada", "North America"));
        
mutableMap.remove("USA");
assertTrue(immutableMap.containsKey("USA"));
        
mutableMap.put("Mexico", "North America");
assertFalse(immutableMap.containsKey("Mexico"));


2.使用builder()方法
我們還可以使用  ImmutableMap.builder()  方法建立原始Map中所有條目的副本。
此外,我們可以使用此方法新增原始Map中不存在的其他條目:

ImmutableMap<String, String> immutableMap = ImmutableMap.<String, String>builder()
  .putAll(mutableMap)
  .put("Costa Rica", "North America")
  .build();
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));


3. 使用of() 
最後,我們可以使用ImmutableMap.of()  方法建立一個不可變的Map,其中包含動態提供的一組條目。它最多支援五個鍵/值對:

ImmutableMap<String, String> immutableMap
  = ImmutableMap.of("USA", "North America", "Costa Rica", "North America");
assertTrue(immutableMap.containsKey("USA"));
assertTrue(immutableMap.containsKey("Costa Rica"));


 

相關文章