Eclipse Collections 9.2 Released
New features, more symmetric sympathy and community contributions.
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.