簡體   English   中英

返回ImmutableMap或Map更好嗎?

[英]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,理由是:

  • 方法簽名(包括返回類型)應該是自我記錄的。 評論就像客戶服務:如果您的客戶需要依賴它們,那么您的主要產品就是有缺陷的。
  • 無論是接口還是類,只有在擴展或實現它時才有意義。 給定一個實例(對象),99%的客戶端代碼將無法知道或關心某些東西是接口還是類。 我首先假設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是可以的。

為確保用戶不修改返回的對象,該方法的文檔可以描述返回對象的特征。

這可以說是一個觀點問題,但更好的想法是使用地圖類的接口。 此接口不需要明確地說它是不可變的,但如果您不在接口中公開父類的任何setter方法,則消息將是相同的。

看看下面的文章:

安迪吉布森

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM