Eclipse Collections 9.2 Released

Donald Raab
Oracle Developers
Published in
4 min readMay 21, 2018

New features, more symmetric sympathy and community contributions.

Good symmetry at St. Paul’s

Eclipse Collections is a collections framework for Java. It has optimized List, Set and Map implementations with a rich and fluent API. The library provides additional data structures not found in the JDK like Bags, Multimaps and BiMaps. The framework also provides primitive versions of Lists, Sets, Bags, Stacks and Maps with a rich and fluent API. There is support for both Mutable and Immutable versions of all containers in the library.

There were nine developers who contributed to the Eclipse Collections 9.2.0 release. I want to thank everyone who made a contribution. If this was your first contribution to an open source project and/or Eclipse Collections, congratulations and welcome!

The release notes for Eclipse Collections 9.2.0 are here.

Features, Features, Features!

We all love new features in a framework, especially one we use on a daily basis. Since we started compiling with Java 8 in Eclipse Collections 8.0, we have been enjoying new flexibility for adding new APIs in minor releases by using default methods. Here are some of the new API additions that were added in Eclipse Collections 9.2.

Welcome: flatCollectWith

The first story of symmetry improvements arrives in form of flatCollectWith on RichIterable. We have had flatCollect since version 1.0 of the framework. We have also had collect and collectWith. Now we have improved symmetry having both flatCollect and flatCollectWith. Here’s an example of code using flatCollectWith.

@Test
public void flatCollectWith()
{
MutableList<Integer> list =
Lists.mutable.with(5, 4, 3, 2, 1);
MutableList<Integer> result =
list.flatCollectWith(Interval::fromTo, 1);

MutableList<Integer> expected = mList(
5, 4, 3, 2, 1,
4, 3, 2, 1,
3, 2, 1,
2, 1,
1);
Assert.assertEquals(expected, result);
}

Welcome: toSortedMapBy

Our second story of symmetry arrives in the form of toSortedMapBy on RichIterable. We have had toSortedBagBy since 6.0. We have had to toSortedListBy and toSortedSetBy since 1.0.

@Test
public void toSortedMapBy()
{
MutableList<Integer> list =
Lists.mutable.with(4, 3, 2, 1);
MutableSortedMap<Integer, Integer> map =
list.toSortedMapBy(i -> i % 2, k -> k, v -> v);
Assert.assertEquals(
SortedMaps.mutable.with(
Comparators.byFunction(i -> i % 2),
4, 2, 3, 1),
map);
}

Welcome: Bag.selectDuplicates

We’ve had selectByOccurrences on Bag since 3.0. Now we have a short-cut for selecting all occurrences greater than one.

@Test
public void selectDuplicates()
{
MutableBag<Integer> bag =
Bags.mutable.with(1, 2, 2, 3, 3, 3);
MutableBag<Integer> duplicates =
bag.selectDuplicates();

Assert.assertEquals(
Bags.mutable.with(2, 2, 3, 3, 3),
duplicates);
}

Welcome: Bag.selectUnique

The symmetric method to selectDuplicates is selectUnique. Unlike selectDuplicates which returns a Bag, selectUnique returns a Set.

@Test
public void selectUnique()
{
MutableBag<Integer> bag =
Bags.mutable.with(1, 2, 2, 3, 3, 3);
MutableSet<Integer> unique =
bag.selectUnique();

Assert.assertEquals(
Sets.mutable.with(1),
unique);
}

Welcome: chunk (for primitive collections)

The symmetry is strong in this one. We have had chunk for object collections since version 1.0.

@Test
public void chunk()
{
IntList list = IntInterval.oneTo(10);
RichIterable<IntIterable> chunks = list.chunk(2);

Verify.assertSize(5, chunks);
String string = chunks.makeString("/");
Assert.assertEquals(
"[1, 2]/[3, 4]/[5, 6]/[7, 8]/[9, 10]",
string);
}

Welcome: newEmpty (for primitive collections)

We’ve had newEmpty for our object collections since 1.0. The method newEmpty gives you an empty version of the same collection type. Now we have the same method for primitive collections.

@Test
public void newEmpty()
{
MutableIntList empty1 = IntLists.mutable.empty();
MutableIntList empty2 = empty1.newEmpty();

Assert.assertEquals(empty1, empty2);
Assert.assertNotSame(empty1, empty2);
}

Welcome: OrderedMapAdapter

This is missing symmetry of a sort. We have had adapters for List, Set, SortedSet, Collection, Map since 1.0. While there is no OrderedMap interface in Java, there is an OrderedMap implementation, which is called LinkedHashMap. You could always adapt a LinkedHashMap as a MutableMap. Now you can adapt it and get back an OrderedMap or a MutableOrderedMap. Of course, the next thing we will eventually want on RichIterable is toOrderedMap.

@Test
public void orderedMapAdapter()
{

MutableList<Integer> keys = Lists.mutable.with(3, 2, 1);
MutableOrderedMap<Object, Object> orderedMap =
OrderedMaps.adapt(
keys.injectInto(
new LinkedHashMap<>(),
(map, each) -> {
map.put(each, each);
return map;
}));

LinkedHashMap<Object, Object> expected = new LinkedHashMap<>();
expected.put(3, 3);
expected.put(2, 2);
expected.put(1, 1);

Assert.assertEquals(expected, orderedMap);
Assert.assertEquals(keys, orderedMap.keysView().toList());
Assert.assertEquals(Interval.fromTo(3, 1), orderedMap.toList());
}

Update: Here’s an example using forEachWithIndex to populate the orderedMap.

@Test
public void orderedMapAdapter()
{
MutableOrderedMap<Integer, Integer> orderedMap =
OrderedMaps.adapt(new LinkedHashMap<>());

MutableList<Integer> keys = Lists.mutable.with(3, 2, 1);
keys.forEachWithIndex(orderedMap::put);

Map<Object, Object> expected = new LinkedHashMap<>();
expected.put(3, 0);
expected.put(2, 1);
expected.put(1, 2);

Assert.assertEquals(expected, orderedMap);
Assert.assertEquals(keys, orderedMap.keysView().toList());
Assert.assertEquals(Interval.zeroTo(2), orderedMap.toList());
}

Welcome: toStringOfItemToCount (for primitive bags)

We’ve had this method available on object Bags since version 3.0. Now toStringOfItemToCount is available for all primitive Bag implementations.

@Test
public void toStringOfItemToCount()
{
MutableIntBag bag = IntBags.mutable.with(1, 2, 2, 3, 3, 3);
String string = bag.toStringOfItemToCount();

Assert.assertEquals("{1=1, 2=2, 3=3}", string);
}

Welcome: Two new Collectors on Collectors2

We now have aggregateBy and countByEach on Collectors2. The method aggregateBy gives us symmetry on Collectors2 with the same method on RichIterable. The method countByEach on the other hand, currently has no equivalent implementation in the RichIterable API. This method is experimental in nature, and if it proves useful enough, we may add it as a feature to RichIterable in a future release.

@Test
public void countByEach()
{
MutableBag<Integer> bag = Arrays.asList(5, 4, 3, 2, 1)
.stream()
.collect(Collectors2.countByEach(Interval::oneTo));

MutableBag<Integer> expected = Bags.mutable.empty();
expected.addOccurrences(5, 1);
expected.addOccurrences(4, 2);
expected.addOccurrences(3, 3);
expected.addOccurrences(2, 4);
expected.addOccurrences(1, 5);

Assert.assertEquals(expected, bag);
}

And there is more…

Have a look at some of the other features and improvements listed in the release notes. We look forward to seeing more contributors to Eclipse Collections in the future.

Have fun using Eclipse Collections 9.2 and all of the new features in your Java projects!

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.

--

--

Donald Raab
Oracle Developers

Java Champion. Creator of the Eclipse Collections OSS Java library (https://github.com/eclipse/eclipse-collections). Inspired by Smalltalk. Opinions are my own.