DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. JVM Advent Calendar: API Design of Eclipse Collections

JVM Advent Calendar: API Design of Eclipse Collections

Learn more about Eclipse Collections and the API design.

Nikhil Nanivadekar user avatar by
Nikhil Nanivadekar
·
Dec. 24, 18 · Presentation
Like (7)
Save
Tweet
Share
16.79K Views

Join the DZone community and get the full member experience.

Join For Free

Eclipse Collections is an open-source Java Collections Framework that enables writing functional, fluent code in Java.

History

Eclipse Collections started off as a collections framework named Caramel at Goldman Sachs in 2004. Since then, the framework has evolved, and in 2012, it was open sourced to GitHub as a project called GS Collections. Over the years, around 40 or so developers from the same company have contributed to the collections framework. To maximize the best nature of the open-source project, GS Collections was migrated to the Eclipse Foundation, re-branded as Eclipse Collections in 2015. Now, the framework is fully open to the community, accepting contributions!

Design Goals

Eclipse Collections was designed to provide rich, functional, fluent, and fun APIs along with memory efficient data structures, all the while providing interoperability with Java Collections. It provides missing types like Bag, Multimap, Stack, BiMap, Interval.

Evolution of the Framework

Over the past 14+ years, the framework has matured and the highest interface: RichIterable, which now has more than 100 methods on it. These methods were included on the interface after careful deliberation. Below are the steps we take while adding an API:

1. Use case: the majority of the methods added to the framework are motivated by user requirements. Users will raise either an Issue or directly a Pull Request on the project and then we start the discussion.

2. Static Utility vs API: Eclipse Collections has static utility classes like Iterate, ListIterate, etc. These static utility classes allow us to prototype our features before adding it as an API. If the static utility methods are heavily used, then in subsequent release, we try to implement the method as an API on the collection interface to provide a rich and fluent coding experience.

For example, Iterate#groupByAndCollect() is currently implemented on the static utility. Since the method is used frequently, it justifies adding it as an API on RichIterable to provide a rich, functional, and fluent coding experience. There is an open issue in case you would like to help us out.

3. Covariant Overrides: We override the API methods logically so that the API returns a type, which is true to it’s behavior.

For example, RichIterable has an API called select(), which is similar to filter() and returns all elements of the collections, which evaluate true for the Predicate. Below is how the API is defined on each interface:

// RichIterable
RichIterable<T> select(Predicate<? super T> predicate);

// ListIterable
ListIterable<T> select(Predicate<? super T> predicate);

// MutableList
MutableList<T> select(Predicate<? super T> predicate)


As you can see, select() on
– RichIterable returns a RichIterable
– ListIterable returns a ListIterable
– MutableList returns a MutableList

4. Overloads with Target: Sometimes, it is possible that we need a different collection than the one returned. In order to make it efficient and fluent, we create an overloaded method, which accepts a target collection. The target collections are used to accumulate the results and return the target collection.

For example, as described above, the select() method on a MutableList returns a MutableList. However, what if you want a MutableSet? There is an overloaded select() method available, which takes in a target collection that can be a set.

MutableList<Integer> integers = Lists.mutable.with(
        1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
MutableList<Integer> evens = integers.select(each -> each % 2 == 0);
Assert.assertEquals(Lists.mutable.with(2, 2, 4, 4, 4, 4), evens);

MutableSet<Integer> uniqueEvens = integers.select(
        each -> each % 2 == 0,
        Sets.mutable.empty());
Assert.assertEquals(Sets.mutable.with(2, 4), uniqueEvens);


5. Symmetry:
Eclipse Collections offers primitive collections. We try to maintain symmetry between the object collections and primitive collections to provide a complete user experience.

Implementing an API in Practice

Let us implement a simple API RichIterable#countBy(), which was added in Eclipse Collections release 9.0.0: The motivation for this API was the users mentioning having to collect() a collection in a Bag. In Eclipse Collections, collect() is similar to map(), and Bagis a data structure that maintains a mapping of an object to the count.

MutableList<String> strings = Lists.mutable.with(
        "1", "2", "2", "3", "3", "3", "4", "4", "4", "4");
Bag<Integer> integers = strings.collect(
        Integer::valueOf, 
        Bags.mutable.empty());
Assert.assertEquals(1, integers.occurrencesOf(1));
Assert.assertEquals(2, integers.occurrencesOf(2));
Assert.assertEquals(3, integers.occurrencesOf(3));
Assert.assertEquals(4, integers.occurrencesOf(4));


The above solution to count the integers worked; however, it was not intuitive. An inexperienced developer might have a hard time to implement this solution. So, we decided to add countBy(), and now, the code looks more functional, fluent, and intuitive.

MutableList<String> strings = Lists.mutable.with(
        "1", "2", "2", "3", "3", "3", "4", "4", "4", "4");
Bag<Integer> integers = strings.countBy(Integer::valueOf);
Assert.assertEquals(1, integers.occurrencesOf(1));
Assert.assertEquals(2, integers.occurrencesOf(2));
Assert.assertEquals(3, integers.occurrencesOf(3));
Assert.assertEquals(4, integers.occurrencesOf(4));


Summary

In this blog, I explained the evolution strategy of a mature Java collections library. The aspects we look at are use case, utility vs API, covariant overrides, necessary overloads, and lastly, symmetry.


It is a personal goal to get 1000 stars on our GitHub project, so if you like the framework, show your support and put a star on the repository. 

API Java (programming language) Eclipse Java virtual machine Design Calendar (Apple)

Published at DZone with permission of Nikhil Nanivadekar. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Load Balancing Pattern
  • Why Open Source Is Much More Than Just a Free Tier
  • How To Generate Code Coverage Report Using JaCoCo-Maven Plugin
  • SAST: How Code Analysis Tools Look for Security Flaws

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: