簡體   English   中英

首選可變或不可變 collections 作為方法參數

[英]Preferring mutable or immutable collections as method parameters

我正在編寫一個將在多個地方使用的庫方法。 該方法的參數之一是對象的集合,並且該方法不會改變該集合。 方法簽名應該指定一個可變的還是不可變的集合?

選項 1:可變集合作為參數

public static void foo(List<Bar> list) {
  // ...
}

優點:客戶端可以傳入List<Bar>ImmutableList<Bar>中的任何一個對他們來說更方便。

缺點: list參數不會發生突變並不是很明顯。 客戶必須閱讀文檔和/或代碼來實現這一點。 無論如何,客戶可能會制作不必要的防御性副本。

選項 2:不可變集合作為參數

public static void foo(ImmutableList<Bar> list) {
  // ...
}

優點:客戶可以保證list參數不會發生變化。

缺點:如果客戶端有List<Bar> ,他們必須在調用foo之前先將其轉換為ImmutableList<Bar> 這種轉換浪費了少量時間,並且無論他們喜歡與否,它都是強加給客戶的。


注意:出於這個問題的目的,我們假設所有客戶端都可以使用 Guava 的ImmutableList ,例如因為庫和客戶端代碼都屬於已經在其他地方使用ImmutableList的相同代碼庫。

作為foo() API 的創建者,這不關你的事。 你拿一個清單,你不修改它,就是這樣。 實際上,您的代碼並不關心列表的可變性(這是調用者關心的問題):因此請記錄您的意圖並停在那里。

如果調用者需要保證列表不會被篡改,他們會創建防御性副本,這不是因為您沒有 promise 保持列表不變,而是因為他們需要那個保證。

它遵循我們在方法實現中執行 null 檢查的相同邏輯:需要它是因為我們的代碼需要健壯,而不是因為調用者可以發送 null 參數。

換句話說,按照您打算實現它們的方式記錄您的方法,並將其留給調用者來選擇列表實現。 他們選擇的原因會有所不同(即,並不總是只有您是否會修改列表)。

將其留在List

以下是一些需要考慮的情況:

  • Collections.synchronizedCollection不會修改客戶端的集合。
    • 如果它強制客戶端輸入不可變集合,那么將其設為同步集合是沒有用的,因為不可變集合已經是線程安全的。
  • Collections.frequency不會修改客戶端的集合。
    • 為了檢查頻率,用戶將被迫忍受將元素轉移到新集合的額外開銷。

這些原因並不是 JDK 不公開不可變接口的原因。 這些原因在文檔中進行了解釋。 synchronizedCollection的情況下,雖然它不修改客戶端的集合,但它確實返回了客戶端集合的可修改視圖; 有人會說這個 function 在這里不適用。 但是, frequency和其他查詢功能仍然很強大。

您不應該為了宣傳安全而限制客戶,僅此而已。 應該有更多的理由,否則您的幫助可能會成為客戶的負擔。 在某些情況下,您的目標可能與功能/系統正在實現的目標相矛盾,例如synchronizedCollection示例。

鼓勵安全是件好事,但是讓您的系統將其強加給您的客戶,而系統卻沒有從中受益,那就是濫用權力; 這不是你的決定。


ernest_k在他的回答中提出了一個非常好的觀點,建議您需要分析您的系統應該負責什么,以及客戶應該負責什么。 在這種情況下,集合是否不可變應該由客戶端決定,因為您的系統不關心可變性。 正如他所說,“這不關你的事”,我同意。

暫無
暫無

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

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