[英]Is it better to return an ImmutableMap or a Map?
假設我正在編寫一個應該返回Map的方法 。 例如:
public Map<String, Integer> foo() {
return new HashMap<String, Integer>();
}
在考慮了一段時間之后,我決定在創建Map之后沒有理由修改它。 因此,我想返回一個ImmutableMap 。
public Map<String, Integer> foo() {
return ImmutableMap.of();
}
我應該將返回類型保留為通用Map,還是應該指定我返回一個ImmutableMap?
從一個方面來說,這就是為什么創建接口的原因; 隱藏實現細節。
另一方面,如果我將這樣離開,其他開發人員可能會錯過這個對象是不可變的這一事實。 因此,我不會實現不可變對象的主要目標; 通過最小化可以更改的對象的數量來使代碼更清晰。 甚至最糟糕的是,過了一段時間,有人可能會嘗試更改此對象,這將導致運行時錯誤(編譯器不會對此發出警告)。
如果你正在編寫一個面向公眾的API,並且不變性是你設計的一個重要方面,我肯定會通過讓方法的名稱清楚地表明返回的地圖是不可變的或通過返回具體的類型來明確它。地圖。 在我看來,在javadoc中提到它是不夠的。
由於您顯然正在使用Guava實現,我查看了doc並且它是一個抽象類,因此它確實為您提供了實際的具體類型的靈活性。
如果您正在編寫內部工具/庫,那么返回一個普通的Map
會變得更加可接受。 人們會知道他們正在調用的代碼的內部,或者至少可以輕松訪問它。
我的結論是明確是好的,不要把事情搞得一團糟。
您應該將ImmutableMap
作為返回類型。 Map
包含ImmutableMap
實現不支持的方法(例如put
),並在ImmutableMap
中標記為@deprecated
。
使用棄用的方法將導致編譯器警告,並且大多數IDE將在人們嘗試使用已棄用的方法時發出警告。
這個高級警告比運行時異常更可取,因為你的第一個暗示是出錯了。
另一方面,如果我將這樣離開,其他開發人員可能會錯過這個對象是不可變的這一事實。
你應該在javadocs中提到它。 你知道,開發人員會閱讀它們。
因此,我不會實現不可變對象的主要目標; 通過最小化可以更改的對象的數量來使代碼更清晰。 甚至最糟糕的是,過了一段時間,有人可能會嘗試更改此對象,這將導致運行時錯誤(編譯器不會對此發出警告)。
沒有開發人員發布未經測試的代碼。 當他測試它時,他會拋出異常,他不僅會看到原因,還會看到他試圖寫入不可變地圖的文件和行。
請注意,只有Map
本身是不可變的,而不是它包含的對象。
如果我這樣離開,其他開發人員可能會錯過這個對象是不可變的這個事實
這是事實,但其他開發人員應該測試他們的代碼並確保它被覆蓋。
不過,您還有2個選項可以解決此問題:
使用Javadoc
@return a immutable map
選擇描述性方法名稱
public Map<String, Integer> getImmutableMap() public Map<String, Integer> getUnmodifiableEntries()
對於具體的用例,您甚至可以更好地命名方法。 例如
public Map<String, Integer> getUnmodifiableCountByWords()
你還能做什么?!
你可以退貨
復制
private Map<String, Integer> myMap; public Map<String, Integer> foo() { return new HashMap<String, Integer>(myMap); }
如果您希望許多客戶端修改地圖並且只要地圖只包含少量條目,則應使用此方法。
CopyOnWriteMap
寫入集合上的副本通常在您需要處理時使用
並發性。 但是這個概念也會在你的情況下幫助你,因為CopyOnWriteMap在一個變異操作上創建了一個內部數據結構的副本(例如add,remove)。
在這種情況下,您需要一個圍繞地圖的薄包裝器,它將所有方法調用委托給底層映射,但變量操作除外。 如果調用了一個mutative操作,它會創建一個底層映射的副本,所有進一步的調用都將被委托給該副本。
如果您希望某些客戶端修改地圖,則應使用此方法。
可悲的是,java沒有這樣的CopyOnWriteMap
。 但您可能會找到第三方或自己實施。
最后,您應該記住,地圖中的元素可能仍然是可變的。
肯定會返回一個ImmutableMap,理由是:
這取決於班級本身。 Guava的ImmutableMap
並不打算成為一個可變類的不可變視圖。 如果您的類是不可變的並且具有一些基本上是ImmutableMap
結構,那么創建返回類型ImmutableMap
。 但是,如果您的課程是可變的,請不要。 如果你有這個:
public ImmutableMap<String, Integer> foo() {
return ImmutableMap.copyOf(internalMap);
}
番石榴每次都會復制地圖。 那很慢。 但是如果internalMap
已經是一個ImmutableMap
,那就完全沒問了。
如果你不限制你的類返回ImmutableMap
,那么你可以改為返回Collections.unmodifiableMap
如下所示:
public Map<String, Integer> foo() {
return Collections.unmodifiableMap(internalMap);
}
請注意,這是一個不可變的地圖視圖 。 如果internalMap
發生更改,則Collections.unmodifiableMap(internalMap)
的緩存副本也會發生更改。 然而,我仍然喜歡吸氣劑。
這並沒有回答確切的問題,但是仍然值得考慮是否應該返回地圖。 如果映射是不可變的,那么要提供的主要方法是基於get(key):
public Integer fooOf(String key) {
return map.get(key);
}
這使得API更加緊湊。 如果實際需要地圖,則可以通過提供條目流將其留給API的客戶端:
public Stream<Map.Entry<String, Integer>> foos() {
map.entrySet().stream()
}
然后,客戶端可以根據需要創建自己的不可變或可變映射,或將條目添加到其自己的映射中。 如果客戶端需要知道該值是否存在,則可以返回optional:
public Optional<Integer> fooOf(String key) {
return Optional.ofNullable(map.get(key));
}
不可變地圖是一種地圖。 所以留下返回類型的Map是可以的。
為確保用戶不修改返回的對象,該方法的文檔可以描述返回對象的特征。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.