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,协变覆盖,必要的重载,最后是对称性。


猜你喜欢

转载自blog.51cto.com/14009535/2334613