Nine Features in Eclipse Collections 9.0
CountBy, DistinctBy, Cartesian Product for primitive collections… and more.

In my previous blog post, I described the upcoming release of Eclipse Collections 9.0.
In this post, I will briefly highlight nine features with examples that will be included in the Eclipse Collections 9.0 release. Each example shows what you could do in Eclipse Collections 7.x — 8.x and how it was improved in Eclipse Collections 9.0.
1. CountBy
// Eclipse Collections 7.x - 8.x
MutableBag<String> countsOld =
this.company.getCustomers()
.asLazy().collect(Customer::getCity).toBag();// Eclipse Collections 9.x
MutableBag<String> countsNew =
this.company.getCustomers()
.countBy(Customer::getCity);
It should be easier for developers to both discover and read countBy
versus the previous alternative.
2. DistinctBy
// Eclipse Collections 7.x - 8.x
MutableList<Customer> distinctOld =
this.company.getCustomers()
.distinct(
HashingStrategies.fromFunction(Customer::getCity));// Eclipse Collections 9.x
MutableList<Customer> distinctNew =
this.company.getCustomers()
.distinctBy(Customer::getCity);
DistinctBy
uses distinct
with a HashingStrategy
for its implementation.
3. Primitive Collection Factories work with Primitive Java Streams
// Eclipse Collections 7.x - 8.x
MutableIntList listOld =
IntStream.rangeClosed(1, 100)
.collect(
IntLists.mutable::empty,
MutableIntList::add,
MutableIntList::withAll);// Eclipse Collections 9.x
MutableIntList listNew =
IntLists.mutable.withAll(
IntStream.rangeClosed(1, 100));
There are also immutable factories that take IntStream
, LongStream
and DoubleStream
. Both mutable and immutable factories that accept primitive Java Streams are available across primitive Lists
, Sets
, Bags
, and Stacks
for int
, long
and double
. Symmetric Sympathy strikes again.
4. Factory classes can now create adapters
// Eclipse Collections 7.x - 8.x
MutableList<Object> listAdapter =
ListAdapter.adapt(new ArrayList<>());
MutableSet<Object> setAdapter =
SetAdapter.adapt(new ConcurrentSkipListSet<>());
MutableMap<Object, Object> mapAdapter =
MapAdapter.adapt(new LinkedHashMap<>());// Eclipse Collections 9.x
MutableList<Object> listAdapter =
Lists.adapt(new ArrayList<>());
MutableSet<Object> setAdapter =
Sets.adapt(new ConcurrentSkipListSet<>());
MutableMap<Object, Object> mapAdapter =
Maps.adapt(new LinkedHashMap<>());
Many developers do not realize there are adapter classes for existing JDK types in Eclipse Collections. Adding this short-cut on the factory classes should make it easier to discover.
5. Streams available directly on Immutable Collections
// Eclipse Collections 7.x - 8.x
boolean result =
Lists.immutable.with(1, 2, 3)
.castToList()
.stream()
.anyMatch(i -> i % 2 == 0);// Eclipse Collections 9.x
boolean result =
Lists.immutable.with(1, 2, 3)
.stream()
.anyMatch(i -> i % 2 == 0);
This was a requested feature. It is not obvious that you can call castToList
and then call stream
on an ImmutableCollection
. In this previous post I described the design decision to not have ImmutableCollection
extend Collection
. This is why it was necessary to add stream explicitly.
6. FlatCollect on primitive lazy iterables
// Eclipse Collections 8.x
IntList listOne = IntLists.mutable.with(1, 2, 3);
IntList listTwo = IntLists.mutable.with(4, 5, 6);
MutableList<IntIntPair> pairs = listOne
.flatCollect(i ->
listTwo.collect(j ->
PrimitiveTuples.pair(i, j)),
Lists.mutable.empty());// Eclipse Collections 9.x
IntList listOne = IntLists.mutable.with(1, 2, 3);
IntList listTwo = IntLists.mutable.with(4, 5, 6);
LazyIterable<IntIntPair> pairs =
listOne.asLazy()
.flatCollect(i -> listTwo.asLazy()
.collect(j -> PrimitiveTuples.pair(i, j)));
Previously, you could only flatCollect
directly into a mutable primitive container. This method was an important building block for primitive cartesian product so it could be implemented lazily.
7. Streams available for values on all Object Valued Maps
// Eclipse Collections 7.x - 8.x - Object Maps
boolean result =
Maps.mutable.with(1, 1, 2, 2, 3, 3)
.values()
.stream()
.anyMatch(i -> i % 2 == 0);// Eclipse Collections 9.x - Object Maps
boolean result =
Maps.mutable.with(1, 1, 2, 2, 3, 3)
.stream()
.anyMatch(i -> i % 2 == 0);// Eclipse Collections 7.x - 8.x - PrimitiveObject Maps
boolean primitiveResult =
IntObjectMaps.mutable.<Integer>empty()
.withKeyValue(1, 1)
.withKeyValue(2, 2)
.withKeyValue(3, 3)
.values()
.stream()
.anyMatch(i -> i % 2 == 0);// Eclipse Collections 9.x - PrimitiveObject Maps
boolean primitiveResult2 =
IntObjectMaps.mutable.<Integer>empty()
.withKeyValue(1, 1)
.withKeyValue(2, 2)
.withKeyValue(3, 3)
.stream()
.anyMatch(i -> i % 2 == 0);
All object valued maps implement RichIterable<V>
. This was a conscious design decision made in the early days of Eclipse Collections. Unfortunately, the stream
method is defined on Collection
which Maps
in Eclipse Collections do not extend. So the stream method had to be added explicitly.
8. AverageIfEmpty and MedianIfEmpty on primitive iterables
// Eclipse Collections 7.x - 8.x
double average = IntLists.mutable.empty().average();
// throws java.lang.ArithmeticException
double median = IntLists.mutable.empty().median();
// throws java.lang.ArithmeticException// Eclipse Collections 9.x
double average = IntLists.mutable.empty().averageIfEmpty(0.0);
double median = IntLists.mutable.empty().medianIfEmpty(0.0);
Eclipse Collections had minIfEmpty
and maxIfEmpty
on primitive iterables but did not have the equivalent for average
and median
, which both throw on empty.
9. Primitive Sets now have Cartesian Product
// Eclipse Collections 7.x - 8.x
Set<Integer> a = Sets.mutable.with(1, 2, 3);
Set<Integer> b = Sets.mutable.with(4, 5, 6);
LazyIterable<Pair<Integer, Integer>> pairs =
Sets.cartesianProduct(a, b);// Eclipse Collections 9.x
IntSet a = IntSets.mutable.with(1, 2, 3);
IntSet b = IntSets.mutable.with(4, 5, 6);
LazyIterable<IntIntPair> pairs =
IntSets.cartesianProduct(a, b);
Eventually I hope we will have all of the methods available on Sets
today on the equivalent primitive Sets
classes. There are methods like difference
, symmetricDifference
, powerSet
, etc. on the Sets
class today. Cartesian Product was a good first step to providing better symmetry for primitive collections.
…and there is more. See the detailed release notes here.
I am a Project Lead and Committer for the Eclipse Collections OSS project at the Eclipse Foundation. Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.