Eclipse Collections 9.1 Released

New Features, more languages, better symmetry and other improvements

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.

The Eclipse Collections community continues to grow. There were ten developers who contributed to the Eclipse Collections 9.1.0 release. I want to thank everyone who made a contribution. If this was your first contribution to an open source project, congratulations and welcome!

The release notes for Eclipse Collections 9.1.0 are here:

Multi-language Website

In addition to code contributions, several developers worked on translating our Eclipse Collections Website to other spoken languages. This is an amazing example of how you can use more than just your coding skills to help open source projects. Thank you to both the contributors and reviewers!

Here are our website links:

A Chinese translation is in the works, and we will be looking to add other languages in the future. Please feel to submit an issue or pull request if you’d like to work on a translation to a spoken language you are fluent in.

The Eclipse Collections Katas

Both of the Eclipse Collections katas are now available in Reveal.js as of this release.

We also had our first ever contribution of a live video demonstration of the Eclipse Collections Pet Kata using Eclipse Oxygen presented in Brazilian Portuguese. Great work and thank you Leo!

https://www.youtube.com/watch?v=1TH0tdU_esQ

It would be great to have multi-language translations of our katas as well. Our katas are hosted now as simple markdown files which get translated to web based slides using Reveal.js. Feel free to submit a pull request if you’d like to translate the katas to another spoken language.

New Collectors

Several new Collector implementations were added to the Collectors2 utility class in this release. We continue to look to provide good integration between the Streams library and Eclipse Collections. Here’s an example of using the new countBy Collector with a Stream of String.

@Test
public void countBy()
{
Stream<String> stream = Stream.of(
"One", "Two", "two", "Three", "three", "tHrEe");

Bag<String> counts =
stream.collect(
Collectors2.countBy(String::toLowerCase));

Assert.assertEquals(1, counts.occurrencesOf("one"));
Assert.assertEquals(2, counts.occurrencesOf("two"));
Assert.assertEquals(3, counts.occurrencesOf("three"));
}

You can now consider using the countBy Collector as an alternative to using the groupingBy and counting alternative from the JDK shown below.

@Test
public void groupingByCounting()
{
Stream<String> stream = Stream.of(
"One", "Two", "two", "Three", "three", "tHrEe");

Map<String, Long> counts =
stream.collect(
Collectors.groupingBy(String::toLowerCase,
Collectors.counting()));

Assert.assertEquals(Long.valueOf(1), counts.get("one"));
Assert.assertEquals(Long.valueOf(2), counts.get("two"));
Assert.assertEquals(Long.valueOf(3), counts.get("three"));
}

There were also Collectors added for groupByEach and groupByUniqueKey on the Collectors2 class in this release.

Symmetric Sympathy Continues

You can now use zip with primitive Lists. There are two varieties of zip for primitive Lists.

  1. Zipping a primitive and an object List.
@Test
public void zipPrimitiveWithObject()
{
MutableList<IntObjectPair<String>> zipped =
IntLists.mutable.with(1, 2, 3)
.zip(Lists.mutable.with("one", "two", "three"));

List<IntObjectPair<String>> expected =
Lists.mutable.with(
PrimitiveTuples.pair(1, "one"),
PrimitiveTuples.pair(2, "two"),
PrimitiveTuples.pair(3, "three"));

Assert.assertEquals(expected, zipped);
}

2. Zipping two primitive Lists of the same type.

@Test
public void zipIntToInt()
{
MutableList<IntIntPair> zipped =
IntLists.mutable.with(1, 2, 3)
.zipInt(IntInterval.oneTo(3).asReversed());

List<IntIntPair> expected =
Lists.mutable.with(
PrimitiveTuples.pair(1, 3),
PrimitiveTuples.pair(2, 2),
PrimitiveTuples.pair(3, 1));

Assert.assertEquals(expected, zipped);
}

There is a zip<Type> method for each primitive type. Here is an example of the zipChar method available on CharAdapter, which is an ImmutableCharList. We can obtain a CharAdapter now simply by using the new Strings factory class.

@Test
public void zipCharToChar()
{
ImmutableList<CharCharPair> zipped =
Strings.asChars("hello")
.zipChar(Strings.asChars("hello").asReversed());

List<CharCharPair> expected =
Lists.mutable.with(
PrimitiveTuples.pair('h', 'o'),
PrimitiveTuples.pair('e', 'l'),
PrimitiveTuples.pair('l', 'l'),
PrimitiveTuples.pair('l', 'e'),
PrimitiveTuples.pair('o', 'h'));

Assert.assertEquals(expected, zipped);
}

Abandoning Symmetry for a better design

Sometimes providing good symmetry may not be the best solution to a problem. There has been a method called zipWithIndex available on Eclipse Collections object collections for a very long time. ZipWithIndex was added before we had primitive collections in Eclipse Collections, so its return type unfortunately boxes an Integer for the index. I did not want to add a primitive version of of the same API. Instead, I added a new method to both object and primitive Lists (Symmetry!) called collectWithIndex. CollectWithIndex can be used to implement zipWithIndex by collecting to a ObjectIntPair.

@Test
public void whereIsZipWithIndex()
{
MutableList<Pair<String, Integer>> original =
Lists.mutable.with("1", "2", "3")
.zipWithIndex();

MutableList<ObjectIntPair<String>> improved =
Lists.mutable.with("1", "2", "3")
.collectWithIndex(PrimitiveTuples::pair);

Assert.assertEquals(
original.get(0).getTwo().intValue(),
improved.get(0).getTwo());
Assert.assertEquals(
original.get(1).getTwo().intValue(),
improved.get(1).getTwo());
Assert.assertEquals(
original.get(2).getTwo().intValue(),
improved.get(2).getTwo());
}

Ideally, zipWithIndex would have returned ObjectIntPair, but this type wasn’t available when the API was originally added. Since we don’t like breaking backwards compatibility on existing methods unless there is a very compelling reason to, we’ll probably never change the return type for zipWithIndex. The collectWithIndex method can return any type you want, not just a Pair. I believe collectWithIndex will prove to be a more useful method than zipWithIndex in the long run.

And of there is more…

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

Happy New Year and have fun using Eclipse Collections 9.1 in your Java projects!

Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.