[英]Use of guava immutable collection as method parameter and/or return type
我試圖確定ImmutableList的最佳實踐。 以下是一個簡單的例子,有助於解決我的問題:
例如:
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
//.. do some work
ImmutableList<Foo> fooOther = // something generated during the code
return fooOther;
}
public Collection<Foo> getFooTwo(List<Foo> fooInput){
//.. do some work
List<Foo> fooOther = // something generated during the code
return ImmutableList.copyOf(fooOther);
}
public void doSomethingOne(){
ImmutableCollection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
public void doSomethingTwo(){
Collection<Foo> myFoo = getFooOne(myList);
...
someOtherMethod(myFoo);
}
我的問題:
哪個在應用程序中最有意義? [doSomethingOne和getFooOne]或[doSomethingTwo和fooTwo]? 換句話說,如果你知道你正在使用ImmutableCollections,那么繼續來回和執行copyOf(),或者只是在各處使用Immutable是有意義的嗎?
這些示例是公共方法,可能意味着其他人使用它們。 如果這些方法是私有的並且在內部使用,那么這些答案會改變嗎?
如果用戶嘗試向不可變List添加任何內容,則將拋出異常。 因為他們可能沒有意識到這一點,顯然返回一個ImmutableCollection而不是Collection會更有意義嗎?
通常,明智的做法是不在已聲明的返回類型中提交特定實現,但我們將不可變類型視為異常。 聲明返回類型為Immutable*
有幾個原因:
null
。 asList()
或reverse()
方法。 Immutable*
字段,你可以為某人保存一個copyOf()
調用。 (但請注意,如果他確實包含copyOf()
,即使您沒有聲明返回類型,它也會為大多數不可變輸入短路。) 基本上,我只是來自https://github.com/google/guava/wiki/TenThingsAboutImmutableCollections ,您可能想要完整地查看。
如果我理解你的意圖,設計getFooXxx
以制作一個可變 - 可變列表的不可變副本的正確方法是這樣的:
/**
* Returns an <b>immutable copy</b> of input list.
*/
public ImmutableList<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableList.copyOf(input);
}
為什么?
ImmutableList.copyOf()
會發揮作用, ImmutableList
是 ,事實上,一個ImmutableCollection
但為什么你想隱藏有關信息ImmutableList
從用戶? 如果他想要,他會寫Iterable foo = immutableCopyOfFoo(mutableFoo);
相反,但99%他會使用ImmtableList, ImmutableList
做出了一個承諾 - “我是不變的,如果你試圖改變我,我會把所有事情搞砸!” 最后但並非最不重要 - 建議的方法在內部使用是不必要的 ; 只是用
someOtherMethod(ImmutableList.copyOf(foo));
直接在你的代碼中......
您應該檢查@ChrisPovirk的答案 (並鏈接到該答案中的wiki)以了解即當List<Foo> input
包含null
時,如果您嘗試制作不可變副本,則會在運行時產生令人討厭的NPE ...
編輯回答評論#1:
Collection
合同不如List
的那么嚴格; 即,集合不保證任何元素的順序(“有些是有序的,有些是無序的”),而List則是(“有序集合(也稱為序列)”)。
如果輸入是List,則表明訂單很重要,因此輸出應保證相同。 設想:
public ImmutableCollection<Foo> immutableCopyOfFoo(List<Foo> input){
return ImmutableSortedSet.copyOf(input, someFancyComparator);
}
它聞起來不對勁。 如果您不關心訂單,那么方法簽名可能是immutableCopyOfFoo(Collection<Foo> input)
? 但這取決於具體的用例。
我通常的做法是:
接受參數列表(因此界面更易於客戶端使用)
如果性能/內存使用/線程安全很重要,請將提供的List的內容復制到為您的類使用而優化的數據結構中
當返回一個ImmutableList時,ImmutableList應該是返回類型(因為它給調用者更多關於它如何使用返回值的信息)
當返回List的可變實現時,List應該是返回類型,除非返回類型的其他內容很重要(線程安全,作為一個壞*示例)
*這是一個糟糕的例子,因為如果您的返回值需要是線程安全的,那么可能意味着您的代碼出現了其他問題。
將List / ImmutableList替換為任何不可變集合類型。
public ImmutableCollection<Foo> getFooOne(ImmutableList<Foo> fooInput){
ImmutableList<Foo> fooOther= fooInput;
return ImmutableList.copyOf(fooOther);
}
這毫無意義。 你為什么要復制一個不可變的集合? 不變性的全部意義在於:它無法改變,所以你不妨重復使用它。
public Collection<Foo> getFooTwo(List<Foo> fooInput){
ImmutableList<Foo> fooOther= ImmutableList.copyOf(fooInput);
return ImmutableList.copyOf(fooOther);
}
??? 為什么兩次??? 這可以:
public Collection<Foo> getFooTwo(List<Foo> fooInput){
return ImmutableList.copyOf(fooInput);
}
ImmutableList.copyOf(Collection)
非常智能,可以ImmutableList
修改ImmutableList
,並為其他所有內容創建一個新的ImmutableList
。
您應該始終在公共接口上使用標准JRE類。 在Guava的Immutable...
類上沒有額外的方法,所以你沒有獲得任何編譯時的安全性:任何對這些對象進行更改的嘗試只會在運行時失敗(但請參閱Bart的評論)。 您應該在返回集合的方法中記錄它們是不可變的。
如果您擔心並發修改,則應該在公共方法上提供列表的防御性副本,但是可以在私有方法參數上指定ImmutableCollection
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.