JVM Advent Calendar:Eclipse集合的API設計

歷史

Eclipse Collections於2004年在Goldman Sachs開始作爲一個名爲Caramel的集合框架開始。從那時起,該框架已經發展,並且在2012年,它作爲一個名爲GS Collections的項目開放給GitHub。多年來,大約40名來自同一公司的開發人員爲集合框架做出了貢獻。爲了最大限度地發揮開源項目的最佳性質,GS Collections被遷移到Eclipse Foundation,在2015年重新命名爲Eclipse Collections。現在,該框架對社區完全開放,接受貢獻!

設計目標

Eclipse Collections旨在提供豐富,功能,流暢,有趣的API以及內存高效的數據結構,同時提供與Java Collections的互操作性。它提供了缺失的類型,如BagMultimapStackBiMapInterval

框架的演變

在過去14年多的時間裏,該框架已經成熟並具有最高的界面:RichIterable現在有超過100種方法。經過仔細考慮後,這些方法被包含在界面中。以下是我們在添加API時採取的步驟:

1.用例:  添加到框架中的大多數方法都是出於用戶需求。用戶將在項目中提出問題或直接提出請求,然後我們開始討論。

2.靜態實用程序與API: Eclipse集合具有靜態實用程序類,如IterateListIterate等。這些靜態實用程序類允許我們在將其添加爲API之前對我們的功能進行原型設計。如果大量使用靜態實用程序方法,那麼在後續版本中,我們嘗試將該方法實現爲集合接口上的API,以提供豐富而流暢的編碼體驗。

例如,  Iterate#groupByAndCollect()目前在靜態實用程序上實現。由於該方法經常使用,因此可以將其作爲API添加,RichIterable以提供豐富,功能和流暢的編碼體驗。如果您想幫助我們,有一個未解決的問題

3.協變覆蓋:我們在邏輯上覆蓋API方法,以便API返回一個類型,這對於它的行爲是正確的。

例如,  RichIterable有一個名爲的API select(),它類似於filter()並返回集合的所有元素,它們的值爲true Predicate以下是在每個界面上定義API的方式:

// RichIterable
RichIterable < T >  select(謂詞<? super  T >  謂詞);

// ListIterable
ListIterable < T >  select(謂詞<? super  T >  謂詞);

// MutableList
MutableList < T >  select(謂詞<? super  T >  謂詞)


如你所見,  select()on 
RichIterable返回a RichIterable
ListIterable返回a ListIterable
MutableList返回aMutableList

4.使用Target重載:有時,我們可能需要與返回的集合不同的集合。爲了使其高效和流暢,我們創建了一個重載方法,它接受目標集合。目標集合用於累積結果並返回目標集合。

例如,如上所述,a上的select()方法MutableList返回a MutableList但是,如果你想要一個MutableSet怎麼辦?有一個select()可用的重載方法,它接收可以是一個集合的目標集合。

MutableList < Integer >  整數 =  列表。可變的。用(
        1,2,2,3,3,3,4,4,4,4);
MutableList < 整數>  找齊 =  整數。選擇(每個 - >  每個 % 2  ==  0);
斷言。的assertEquals(解釋。可變的。與(2,2,4,4,4,4),找齊);

MutableSet < Integer >  uniqueEvens  =  整數。選擇(
        每個 - >  每個 % 2  ==  0,
        集。可變的。empty());
斷言。的assertEquals(集。可變。與(2,4),uniqueEvens);


5.對稱性:
 Eclipse Collections提供原始集合。我們嘗試保持對象集合和原始集合之間的對稱性,以提供完整的用戶體驗。

在實踐中實施API

讓我們實現一個簡單的API RichIterable#countBy(),它在Eclipse Collections版本9.0.0中添加:這個API的動機是用戶提到必須在collect()一個集合中Bag在Eclipse Collections中,  collect()類似於map(),並且Bag是一個維護對象到計數的映射的數據結構。

MutableList < String >  strings  =  Lists。可變的。用(
        “1”,“2”,“2”,“3”,“3”,“3”,“4”,“4”,“4”,“4”);
Bag < Integer >  整數 =  字符串。收集(
        Integer :: valueOf,
        包包。可變的。empty());
斷言。的assertEquals(1,整數。occurrencesOf(1));
斷言。的assertEquals(2,整數。occurrencesOf(2));
斷言。的assertEquals(3,整數。occurrencesOf(3));
斷言。的assertEquals(4,整數。occurrencesOf(4));


以上計算整數的解決方案有效; 但是,它並不直觀。沒有經驗的開發人員可能很難實現此解決方案。因此,我們決定添加countBy(),現在,代碼看起來更實用,更流暢,更直觀。

MutableList < String >  strings  =  Lists。可變的。用(
        “1”,“2”,“2”,“3”,“3”,“3”,“4”,“4”,“4”,“4”);
Bag < Integer >  整數 =  字符串。countBy(Integer :: valueOf);
斷言。的assertEquals(1,整數。occurrencesOf(1));
斷言。的assertEquals(2,整數。occurrencesOf(2));
斷言。的assertEquals(3,整數。occurrencesOf(3));
斷言。的assertEquals(4,整數。occurrencesOf(4));


摘要

在這篇博客中,我解釋了成熟Java集合庫的演化策略。我們看到的方面是用例,實用程序與API,協變覆蓋,必要的重載,最後是對稱性。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章