2009-01-25 56 views
2

我在大約一年前發現了CollectionUtils類,並且類似,收集和轉換的一些方法看起來非常酷,但是,我還沒有找到一種不使用語法上更清潔的方法和\或者更簡單的方法是用一個簡單的循環來編寫邏輯。Apache CollectionUtils的好用處

有沒有發現這些方法(transform,predicatedCollection,collect等)的獨特\有用的用法,例如將變換器或謂詞作爲參數的方法?

回答

2

我認爲關鍵問題是設計/編碼的靈活性。

如果您有一個用例(例如,選擇滿足某些特定條件的集合的成員),那麼手工編寫相對簡單的循環。另一方面...

假設一組可能的條件變得很大,或者甚至可以在運行時即時動態編寫(即使是動態的,基於用戶輸入/交互)。或者假設有幾個非常複雜的條件可以與操作員(例如A和B,C而不是D等)組合成更多的情況。

假設在做出選擇之後,還有一些其他處理是在結果集合上完成的。

現在考慮可能由暴力編寫上述內聯方法導致的代碼結構:包含複雜決策過程以確定要執行哪些測試的外循環,與代碼與收集的「倖存」成員做一件或多件事情。這樣的代碼往往是(並且特別是隨着時間的推移而隨着維護而變化)難以理解並且難以修改而沒有引入缺陷的風險。

所以關鍵是要追求的戰略,其中每個方面:

  • 基本的「選擇什麼」的過程,
  • 謂詞表達基本準則,
  • 了組成謂詞合併運營,並
  • 對數值進行操作的變壓器,

可以獨立編碼和測試,th en根據需要拼合在一起。

0

我不知道我跟你的說法...

的簡單循環增加了複雜性,並且比用理性的名字通話較少的「可讀性和明顯的」。

重構福音佈道者會聲稱你的目標通常應該是創建調用其他操作的扁平函數和短函數。雖然addAll,find和這些方法很容易實現,但避免它們需要讀者掌握比單個單詞更復雜的內容,並可能導致代碼複製。

恕我直言,CollectionUtils實際上比標準的Java收集庫提供清潔操作。

+0

儘管我原則上同意,但有些人會認爲對CollectionUtils的調用比簡單的循環更不可讀。不要誤解我,有一些例如isEmpty這樣的呼叫是非常有用的IMO。 – javamonkey79 2009-01-25 02:51:09

+0

不要誤會我的意思,它不像我總是使用電話...... :) – Uri 2009-01-25 04:06:25

1

雖然我原則上同意Uri,但沒有關閉或函數文字或任何其他東西,Java實際上使用諸如collect,transform等方法的語法成本相當高。在很多情況下,實際的代碼行數是如果你已經寫了簡單的循環,那麼它是相同的還是更大的。 addAll,removeAll和所有他們不把函數對象作爲參數的朋友是不可或缺的。

所有這一切也同樣適用於Google Collections API

Sun有能力解決Java 7中的這些問題,但它有appears they won't。懦夫。

+0

是的,你讀了我的想法。我也同意原則上的Uri,但還沒有找到一個可以保存任何東西的好OO案例。 – javamonkey79 2009-01-25 02:49:27

0

雖然我們不使用CollctionUtils我們已經實施了幾個類似的實用程序我們的自我和那些我們經常使用

空(系列三)

測試集合,字符串和這樣的emptyness

有(...)

,只有回報!空(...)

mapToProperty(集合C,String屬性,類NEWTYPE)

這個使用反射來調用T1的集合映射到T2的集合「屬性」

破滅(集合C,字符串SEP)

在SEP分隔STRI ng與元素c

2

collect()在您可能有替代表示的對象時非常有用。

例如,最近我正在處理一段代碼,它需要匹配來自兩個不同來源的對象列表。這些對象具有不同的類別,因爲它們在代碼中的不同位置使用,但爲了我的目的,它們具有相同的相關概念(即它們都具有ID,都具有屬性路徑,都具有「級聯」標誌等) 。

我發現定義這些屬性的簡單中間表示(作爲內部類)要容易得多,爲兩個具體對象類定義轉換器(同樣非常簡單,因爲它只是使用相關存取器方法來獲取屬性),然後使用collect()將我的傳入對象轉換爲中間表示。一旦他們在那裏,我可以使用標準集合方法來比較和操縱這兩個集合。因此,作爲一個(半)具體的例子,假設我需要一種方法來檢查表示層中的對象集是緩存在數據層中的對象的子集。通過上面這個概括的方法將做這樣的事:

public boolean isColumnSubset(PresSpec pres, CachedDataSpec dataSpec) 
{ 
    final List<IntermediateRepresentation> presObjects = CollectionUtils.collect(pres.getObjects(), PRES_TRANSFORMER); 
    final List<IntermediateRepresentation> dataObjects = CollectionUtils.collect(dataSpec.getCached(), DATA_TRANSFORMER); 

    return dataObjects.containsAll(presObjects); 
}

對我來說這是更加易讀,到最後一行傳達的方法是什麼,比環路相當於一個真正意義上的:

public boolean isColumnSubset(PresSpec pres, CachedDataSpec dataSpec) 
{ 
    for (PresSpecificObject presObj : pres.getObjects()) 
    { 
     boolean matched = false; 
     for (CachedDataObject dataObj : dataSpec.getCached()) 
     { 
     if (areObjectsEquivalent(presObj, dataObj)) // or do the tests inline but a method is cleaner 
     { 
      matched = true; 
      break; 
     } 
     } 

     if (matched == false) 
     { 
     return false; 
     } 
    } 

    // Every column must have matched 
    return true; 
}

這兩個可能是有效的,但在可讀性方面,我會說,第一個更容易立即理解。儘管整體上代碼更多(由於定義了一個內部類和兩個變換器),所以將遍歷實現與實際的「真或假」邏輯分離使得後者更加清晰。另外,如果你有任何KLOC指標,它也不可能成爲珠寶。 ;-)