10 Features in Eclipse Collections 10.0

Donald Raab
4 min readAug 1, 2019

--

The sun has set on the Eclipse Collections 10.0 release.

My Top 10 List

In this post, I will share my favorite ten features included in the Eclipse Collections 10.0 release.

1. Stream for Primitive Lists

Now you can call primitiveStream on primitive Lists. The method primitiveStream is available on Int, Long and DoubleLists.

@Test
public void primitiveListToPrimitiveStream()
{
IntStream intStream1 =
IntLists.mutable.with(1, 2, 3, 4, 5)
.primitiveStream();
IntStream intStream2 =
IntLists.immutable.with(1, 2, 3, 4, 5)
.primitiveStream();
LongStream longStream1 =
LongLists.mutable.with(1L, 2L, 3L, 4L, 5L)
.primitiveStream();
LongStream longStream2 =
LongLists.immutable.with(1L, 2L, 3L, 4L, 5L)
.primitiveStream();
DoubleStream doubleStream1 =
DoubleLists.mutable.with(1.0, 2.0, 3.0, 4.0, 5.0)
.primitiveStream();
DoubleStream doubleStream2 =
DoubleLists.immutable.with(1.0, 2.0, 3.0, 4.0, 5.0)
.primitiveStream();
}

2. toMap with a target Map

The method toMap has been overloaded to allow a target map to be passed in as a parameter.

@Test
public void toMapWithTarget()
{
MutableList<Integer> list =
Lists.mutable.with(1, 2, 3, 4, 5);
Map<String, Integer> map =
list.toMap(String::valueOf,
each -> each,
new LinkedHashMap<>());
Map<String, Integer> expected = new LinkedHashMap<>();
expected.put("1", 1);
expected.put("2", 2);
expected.put("3", 3);
expected.put("4", 4);
expected.put("5", 5);
Assert.assertEquals(expected, map);
}

3. RichIterable toBiMap

With Eclipse Collections 10.0, you can now convert any RichIterable to a BiMap.

@Test
public void toBiMap()
{
MutableBiMap<String, Integer> expected =
BiMaps.mutable.with("1", 1, "2", 2, "3", 3);
MutableBiMap<String, Integer> biMap =
Lists.mutable.with(1, 2, 3).toBiMap(String::valueOf, i -> i);
Assert.assertEquals(expected, biMap);
}

4. fromStream on Collection Factories

We can now construct a Collection from a Stream using fromStream on each of the Collection factories for List, Set, Bag, and Stack.

@Test
public void fromStreamOnCollectionFactories()
{
MutableList<Integer>
list = Lists.mutable.fromStream(Stream.of(1, 2, 3, 4, 5));
Assert.assertEquals(
Lists.mutable.with(1, 2, 3, 4, 5), list);
MutableSet<Integer> set =
Sets.mutable.fromStream(Stream.of(1, 2, 3, 4, 5));
Assert.assertEquals(
Sets.mutable.with(1, 2, 3, 4, 5), set);
MutableBag<Integer> bag =
Bags.mutable.fromStream(Stream.of(1, 2, 3, 4, 5));
Assert.assertEquals(
Bags.mutable.with(1, 2, 3, 4, 5), bag);
MutableStack<Integer> stack =
Stacks.mutable.fromStream(Stream.of(1, 2, 3, 4, 5));
Assert.assertEquals(
Stacks.mutable.with(1, 2, 3, 4, 5), stack);
}

5. MutableMultimap getIfAbsentPutAll

The method getIfAbsentPutAll on a MutableMultimap is equivalent to getIfAbsentPut on a MutableMap. The difference is that with a Multimap you can put in multiple values.

@Test
public void getIfAbsentPutAll()
{
MutableListMultimap<Integer, Integer> multimap =
Multimaps.mutable.list.with(2, 1);
ImmutableList<Integer> defaultValue =
Lists.immutable.with(1, 2, 3);
MutableList<Integer> oneValue =
multimap.getIfAbsentPutAll(1, defaultValue);
MutableList<Integer> twoValue =
multimap.getIfAbsentPutAll(2, defaultValue);
Assert.assertEquals(defaultValue, oneValue);
Assert.assertEquals(Lists.mutable.with(1), twoValue);
}

6. Bag collectWithOccurrences

You can use this method to transform a collection using all of the unique items in the Bag along with their counts. Specify an ObjectIntToObjectFunction to transform the items an their counts to some resulting object. In the following example, I will collect the items and their counts into ObjectIntPair instances.

@Test
public void collectWithOccurences()
{
MutableBag<String> source =
Bags.mutable.with("1", "2", "2", "3", "3", "3");
MutableBag<ObjectIntPair<String>> targetBag =
source.collectWithOccurrences(PrimitiveTuples::pair);
MutableBag<ObjectIntPair<String>> expected =
Bags.mutable.with(
PrimitiveTuples.pair("1", 1),
PrimitiveTuples.pair("2", 2),
PrimitiveTuples.pair("3", 3));
Assert.assertEquals(expected, targetBag);
}

7. Reduce / reduceIfEmpty for Primitive Iterables

The method reduce will apply a two argument (long, int) function which returns a long for each element of the collection. This allows for a widening of the result type so as not to overflow on functions like sum. In the case of an empty collection, a NoSuchElementException will be thrown.

@Test
public void reducePrimitiveIterables()
{
MutableIntList list =
IntLists.mutable.with(1, 2, 3, 4, 5);
long sum = list.reduce(Long::sum);
Assert.assertEquals(15L, sum);
Assert.assertEquals(list.sum(), sum);
Verify.assertThrows(
NoSuchElementException.class,
()-> IntLists.mutable.empty().reduce(Long::sum));
}

If you would like to safely handle the case of empty, you can use reduceIfEmpty and specify a default value to return.

@Test
public void reduceIfEmptyPrimitiveIterables()
{
MutableIntList list =
IntLists.mutable.with(1, 2, 3, 4, 5);
long sum = list.reduceIfEmpty(Long::sum, 0L);
Assert.assertEquals(15L, sum);
Assert.assertEquals(list.sum(), sum);
Assert.assertEquals(0L,
IntLists.mutable.empty()
.reduceIfEmpty(Long::sum, 0L));
}

8. RichIterable countByEach

The method countByEach is similar to groupByEach and flatCollect. All three take a Function which returns an Iterable. The result in the case of countByEach is a Bag. In the following example, I count all of the methods by their names for three classes. The count of methods will include overloads and overrides of the methods.

@Test
public void countByEach()
{
MutableList<Class<?>> classes =
Lists.mutable.with(
RichIterable.class,
MutableList.class,
ImmutableList.class);
Bag<String> methodNames =
classes.countByEach(each ->
ArrayAdapter.adapt(each.getMethods())
.collect(Method::getName));
Assert.assertEquals(8,
methodNames.occurrencesOf("countByEach"));
Assert.assertEquals(16,
methodNames.occurrencesOf("groupByEach"));
Assert.assertEquals(2,
methodNames.occurrencesOf("sortThis"));
}

9. Create Primitive Map from Iterable

You can now create a primitive Map from an Iterable with two provided functions. One Function is used to calculate the key, and the other is used to calculate the value. This method is very similar the method toMap on RichIterable. The difference is that it works with any primitive Map.

@Test
public void createPrimitiveMapFromIterable()
{
Iterable<Integer> integers = Interval.oneTo(5);
MutableIntIntMap map =
IntIntMaps.mutable.from(
integers,
key -> key,
value -> value);
MutableIntIntMap expected = IntIntMaps.mutable.empty()
.withKeyValue(1, 1)
.withKeyValue(2, 2)
.withKeyValue(3, 3)
.withKeyValue(4, 4)
.withKeyValue(5, 5);
Assert.assertEquals(expected, map);
}

10. Convert Iterable to Primitive Collections

Before Eclipse Collections 10.0, if you wanted to convert an Iterable of boxed primitive types to a primitive Collection (e.g. Integer -> int), you would have to first convert the Iterable to a Collection or a Stream. In the case of a Stream, you could then use one of the stock primitive Collectors in Collectors2 to convert to a primitive Collection. Now you can use the following factory methods to convert from Iterable of some boxed value like Integer to a primitive Collection. This works for all of the boxed primitive types, across all supported primitive Collection types.

@Test
public void convertFromIterableToPrimitiveCollection()
{
Iterable<Integer> iterable = Interval.oneTo(5);
IntInterval intInterval = IntInterval.oneTo(5);

MutableIntList mIntList =
IntLists.mutable.withAll(iterable);
ImmutableIntList iIntList =
IntLists.immutable.withAll(iterable);

Assert.assertEquals(intInterval, mIntList);
Assert.assertEquals(intInterval, iIntList);

MutableIntSet mIntSet =
IntSets.mutable.withAll(iterable);
ImmutableIntSet iIntSet =
IntSets.immutable.withAll(iterable);

Assert.assertEquals(intInterval.toSet(), mIntSet);
Assert.assertEquals(intInterval.toSet(), iIntSet);

MutableIntBag mIntBag =
IntBags.mutable.withAll(iterable);
ImmutableIntBag iIntBag =
IntBags.immutable.withAll(iterable);

Assert.assertEquals(intInterval.toBag(), mIntBag);
Assert.assertEquals(intInterval.toBag(), iIntBag);
}

I hope you enjoy all of the new features in Eclipse Collections 10.0!

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

--

--

Donald Raab
Donald Raab

Written by Donald Raab

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

No responses yet