The release of Eclipse Collections 11.0.0, an open source collections library for Java compatible with Java collection types, provides new methods and features for improved performance. the ClassComparer
class was introduced to compare the methods of two classes and show the similarities and differences.
Originally named GS Collections by its creator Don Raab, the frame was donated to the Eclipse Foundation in December 2015 and renamed Eclipse Collections. Version 11.0.0 is the first release since version 10.4 in August 2020. Eclipse collections, maintained by these committers and project managers, are built and tested with JDK 8, 11, 17 and 18 in early access.
Various methods, such as selectWithIndex
and rejectWithIndex
have been added to filter elements based on the index and value of a OrderedIterable
Where ListIterable
:
var exampleList = Lists.mutable.with(1, 2, 3, 4, 5);
var selectWithIndexList =
exampleList.selectWithIndex((value, index) -> value + index < 6);
assertEquals(Lists.mutable.with(1, 2, 3), selectWithIndexList);
var rejectWithIndexList =
exampleList.rejectWithIndex((value, index) -> value + index < 6);
assertEquals(Lists.mutable.with(4,5), rejectWithIndexList);
Primitive iterables can be converted to a MutableList
either with the toSortedList
with a Comparator
as an argument or the toSortedListBy
by providing a Function
:
var exampleSet = Sets.mutable.with(1, 2, 3, 4, 5);
var sortedList = exampleSet.toSortedList((val1, val2) -> val2 - val1);
var expected = Lists.mutable.with(5, 4, 3, 2, 1);
assertEquals(expected, sortedList);
var sortedListBy = exampleSet.toSortedListBy(Math::negateExact);
assertEquals(expected, sortedListBy);
Various methods, as detailed by Sirisha Pratha in parts 1 and 2 of her blog series, have been added to Set
. The first method, union
combines the elements of two sets:
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2, 3, 4, 5);
assertEquals(expectedSet, set1.union(set2));
the intersect
selects the elements present in the two sets:
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(3);
assertEquals(expectedSet, set1.intersect(set2));
Another new method, difference
keeps the unique elements of the first set:
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2);
assertEquals(expectedSet, set1.difference(set2));
the symmetricDifference
keeps elements that are unique in one of two sets:
var set1 = Sets.mutable.with(1, 2, 3);
var set2 = Sets.mutable.with(3, 4, 5);
var expectedSet = Sets.mutable.with(1, 2, 4, 5);
assertEquals(expectedSet, set1.symmetricDifference(set2));
the isSubsetOf
the method returns true
if all the elements of the first set are present in the second set:
var set1 = Sets.mutable.with(1, 2);
var set2 = Sets.mutable.with(1, 2, 3);
assertTrue(set1.isSubsetOf(set2));
assertFalse(set2.isSubsetOf(set1));
The strictest version, isProperSubsetOf
Return true
if all the elements of the first set are present in the second set, but the sets are not equal:
var set1 = Sets.mutable.with(1, 2);
var set2 = Sets.mutable.with(1, 2, 3);
assertTrue(set1.isProperSubsetOf(set2));
var set3 = Sets.mutable.with(1, 2);
assertFalse(set1.isProperSubsetOf(set3));
the cartesianProduct
returns all ordered pairs where the first element comes from the pair in the first set and the second element comes from the second set:
var set1 = IntSets.mutable.with(1, 2);
var set2 = IntSets.mutable.with(3, 4);
MutableSet expected = Sets.mutable.with(
PrimitiveTuples.pair(1, 3),
PrimitiveTuples.pair(1, 4),
PrimitiveTuples.pair(2, 4),
PrimitiveTuples.pair(2, 3));
assertEquals(expected, set1.cartesianProduct(set2).toSet());
Newly introduced methods, containsAny
and containsNone
for primitive collections, provide performance advantages over the functional equivalent anySatisfy
and noneSatisfy
at memory cost:
ImmutableIntList list = IntLists.immutable.of(1, 2, 3, 4, 5);
assertTrue(list.containsAny(3, 6));
assertTrue(list.containsAny(new IntArrayList(3, 6)));
assertTrue(list.containsNone(6, 8));
assertTrue(list.containsNone(new IntArrayList(6, 8)));
Pair
and Triple
now contains the isEqual
and isSame
default methods to compare values:
Twin equalTwin = Tuples.twin("James", "James");
assertTrue(equalTwin.isEqual());
Triplet equalTriplet = Tuples.triplet("James", "James", "James");
assertTrue(equalTriplet.isEqual());
Twin sameTwin = Tuples.twin("James", new String("James"));
assertFalse(sameTwin.isSame());
Triplet sameTriplet =
Tuples.triplet("James", "James", new String("James"));
assertFalse(sameTriplet.isSame());
In addition to comparing values, it is now also possible to convert Pair
and Triple
several List
types:
Twin twin = Tuples.twin("James", "Mike");
MutableList pairMutableList = Tuples.pairToList(twin);
FixedSizeList pairFixedSizeList = Tuples.pairToFixedSizeList(twin);
ImmutableList pairImmutableList = Tuples.pairToImmutableList(twin);
Triplet triplet = Tuples.triplet("James", "Mike", "Patrick");
MutableList tripletMutableList = Tuples.tripleToList(triplet);
FixedSizeList tripletFixedSizeList =
Tuples.tripleToFixedSizeList(triplet);
ImmutableList tripletImmutableList =
Tuples.tripleToImmutableList(triplet);
A Bag
is an unordered collection that may contain duplicates. It is mainly used to determine and remove the number of occurrences per element. This release provides several new methods for Bag
which are demonstrated on the basis of the following example:
Bag names = Bags.mutable.with("James", "James", "Mike", "Patrick");
It is now possible to check if the Bag
contains an element:
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
object.equals("Mike")));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
object.equals("Simon")));
Or if the bag contains a specific item with the specified number of occurrences:
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
object.equals("James") && value == 2));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
object.equals("James") && value == 1));
Or check if there are elements with a specific number of occurrences:
assertTrue(names.anySatisfyWithOccurrences((object, value) ->
value == 2));
assertTrue(names.noneSatisfyWithOccurrences((object, value) ->
value > 3));
Collectors2
now contains the toImmutableSortedBagBy
method:
var exampleList = Lists.mutable.with(1, 2, 3, 4);
ImmutableSortedBag bag = exampleList.stream()
.collect(Collectors2.toImmutableSortedBagBy(Math::negateExact));
Comparator comparator = Functions.toIntComparator(Math::negateExact);
ImmutableSortedMap immutableSortedMap = exampleList.stream()
.collect(Collectors2.toImmutableSortedMap(comparator, element -> element, element -> element * 2));
var expected = SortedMaps.mutable.with(comparator, 4, 8, 3, 6, 2, 4, 1, 2);
assertEquals(expected, immutableSortedMap);
Collectors2 also provides the toImmutableSortedMap
, toImmutableSortedMapBy
, toSortedMap
and toSortedMapBy
methods :
List list = List.of(1, 2, 3);
Comparator c =
Functions.toIntComparator(Math::negateExact);
MutableSortedMap map =
list.stream().collect(
Collectors2.toSortedMap(c, e -> e, String::valueOf));
var expected = SortedMaps.mutable.with(c, 1, "1", 2, "2", 3, "3");
assertEquals(expected, map);
With the new newWithMap
and newWithMapIterable
functions on ImmutableMap
it is possible to create immutable maps:
ImmutableMap immutableMap = Maps.immutable.empty();
ImmutableMap resultingImmutableMap =
immutableMap.newWithMap(UnifiedMap.newMapWith(
Tuples.pair("Simon", 1),
Tuples.pair("Mike", 2)));
ImmutableMapIterable immutableMapIterable =
Maps.immutable.empty();
ImmutableMapIterable resultingImmutableMapIterable =
immutableMap.newWithMapIterable(UnifiedMap.newMapWith(
Tuples.pair("Simon", 1),
Tuples.pair("Mike", 2)));
the withMapIterable
and putAllMapIterable
methods have been added to MutableMap
for consistency.
the eclipse-collections-testutils the module now contains ClassComparer
to compare classes. This results in a sort of Venn diagram displaying common methods and class-specific methods, which can optionally be displayed with an experimental Swing UI. Comparing IntIterable.class
and RichIterable.class
displays the following results, which only contain methods beginning with ‘a’ for readability:
new ClassComparer().compareAndPrint(IntIterable.class, RichIterable.class);
Intersection (IntIterable, RichIterable)
----------------------------------------
a:[allSatisfy, anySatisfy, appendString, asLazy]
…
Difference (IntIterable, RichIterable)
--------------------------------------
a:[average, averageIfEmpty]
…
Difference (RichIterable, IntIterable)
--------------------------------------
a:[aggregateBy, aggregateInPlaceBy, allSatisfyWith, anySatisfyWith]
…
Alternately, ClassComparer
offers a constructor argument to optionally compare based on method names, parameter types, and return types:
new ClassComparer(true, true, true)
.compareAndPrint(IntIterable.class, RichIterable.class);
Intersection (org.eclipse.collections.api.IntIterable, org.eclipse.collections.api.RichIterable)
------------------------------------------------------------------------------------------------
a:[appendString(Appendable):void, appendString(Appendable, String):void, appendString(Appendable, String, String, String):void]
…
Difference (org.eclipse.collections.api.IntIterable, org.eclipse.collections.api.RichIterable)
----------------------------------------------------------------------------------------------
a:[allSatisfy(IntPredicate):boolean, anySatisfy(IntPredicate):boolean, asLazy():LazyIntIterable, average():double, averageIfEmpty(double):double]
…
Difference (org.eclipse.collections.api.RichIterable, org.eclipse.collections.api.IntIterable)
----------------------------------------------------------------------------------------------
a:[aggregateBy(Function, Function0, Function2):MapIterable, aggregateBy(Function, Function0, Function2, MutableMapIterable):MutableMapIterable, aggregateInPlaceBy(Function, Function0, Procedure2):MapIterable, allSatisfy(Predicate):boolean, allSatisfyWith(Predicate2, Object):boolean, anySatisfy(Predicate):boolean, anySatisfyWith(Predicate2, Object):boolean, asLazy():LazyIterable]
…
Mutable conversion methods, such as toList
and toSortedSet
, have been available for a while, but their immutable counterparts were not available. It was however possible to convert to immutable using the toImmutable
method, but sometimes required two steps: .toList().toImmutable()
. To improve consistency with mutable peers, toImmutableList
, toImmutableSet
and toImmutableBag
have been added to RichIterable
and other methods may follow in the future.
The full list of changes is available on the GitHub release page.