Eclipse Collections — the features your collections need
Eclipse Collections — the features your collections need
Deny it or not data structures are important. Picking the right one will enormously increase the performance of your program/product/application. It may even get you that perfect job.
Many (mainstream) programming languages come with a collection library. That provides APIs and implementations to make it easy for end-users. These implementations are fast and built to make it easier for end-users.
Providing too many options increases the learning curve of the language, providing too less leads to cumbersome implementation by the users. So languages have to be very careful in what they provide. Java strikes a perfect balance.
Eclipse collections provide optimal and efficient implementations of collections in Java.
Eclipse collections added a few additional data structures that are not natively available in the core Java.
But the most important thing is that Eclipse-Collections provides elegant, functional, and fluent APIs that you can work with.
The top reasons why I love eclipse collections are:
- APIs are awesome. They are
Functional
,Lazy
,Parallel
, andEager
(while optimised) - provides
immutable
andmutable
collections - provides highly-optimised and memory-efficient implementation
Set things up
If you are using a Maven project include the eclipse collection dependencies like below:
<dependency
<groupId>org.eclipse.collections</groupId>
<artifactId>eclipse-collections</artifactId>
<version>10.0.0</version>
</dependency></span>
If you are using Gradle then import it:
compile 'org.eclipse.collections:eclipse-collections-api:10.0.0'
compile 'org.eclipse.collections:eclipse-collections:10.0.0'</span>
Ingredients
The Eclipse Collections consists of the following data structures:
- List
- Set
- Map
- BiMap
- MultiMap
- Bag
- Stack
- Pair and others
All those data structures include the following implementations:
- Mutable
- Immutable
- Lazy
- Parallel
- Ordered
- Sorted
- Fixed
- Primitive and others
Note not all the implementations for all the collections.
Code, Code, Code…
There are few excellent code katas available. They are here.
Let us start with a List
. To instantiate a new mutable list we can do the following:
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);</span>
You can instantiate the list with of
.
MutableList<Integer> firstTenNumbers = Lists.mutable.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);</span>
Thinking why there is of
and with
implementation — check out this blog post.
Retrieval
We can retrieve the elements using classic get(index)
way. The Eclipse Collections provides getFirst()
and getLast()
method to retrieve the first and the last elements respectively.
firstTenNumbers.get(4); // 4
firstTenNumbers.getFirst(); // 0
firstTenNumbers.getLast(); // 9</span>
In functional paradigm, take
| takeWhile
| drop
| dropWhile
APIs are explicit and makes it easy to construct functions. They take and drop certain elements from the list without mutating them. With Eclipse Collections we can do that in Java
.
drop and take
The functions drop
and take
each take a non-negative integer n
. The drop
returns all the elements after the given index while the take
returns all the elements until the given index.
firstTenNumbers.take(3); // 0, 1, 2
firstTenNumbers.drop(3); // 3, 4, 5, 6, 7, 8, 9</span>
The functions drop
and take
can be specified by the following function:
list.take(n) + list.drop(n) == list</span>
dropWhile and takeWhile
They are technically drop
and take
but instead of taking a number as an argument, they take a predicate
function.
The takeWhile
function will return all the values until the predicate returns true.
firstTenNumbers.takeWhile(i -> i % 2 == 0); // 0</span>
The dropWhile
function will return all the values in the list after which the predicate returns true.
firstTenNumbers.dropWhile(i -> i % 2 == 0); // 1, 2, 3, 4, 5, 6, 7, 8, 9</span>
Converters
Often times, we need converters
. The role of converters is to change the list from one form to another. That is from Mutable
to Immutable
or vice versa.
We can achieve that via toMutable (using toList, toMap, toSet, toBag) and toImmutable
function respectively.
MutableList<T> iCanChange = Lists.mutable.with(T… args);
iCanChange.toImmutable(); // From now onwards I cannot Change
ImmutableList<T> iCannotChange = Lists.immutable.with(T… args);
iCannotChange.toMutable(); // From now on I can change</span>
We will need to reverse our list and the API provides us with toReversed
function to achieve the same.
MutableList<T> normalList = Lists.mutable.with(T… args);
normalList.toReversed();</span>
The stack data structure is inbuilt in the library. We can convert the list
into stack
using toStack()
.
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
firstTenNumbers.toStack().pop(4); // 9, 8, 7, 6</span>
There are many other converters available like
toSet
,toSortedSet
,toMap
,toBiMap
, and others
Zip
The function zip
will take a pair of lists
and convert them into list of pairs
. That is:
MutableList<Integer> houseNumbers = Lists.mutable.with(123, 456, 789);
MutableList<String> owners = Lists.mutable.with(“Ram”, “Raj”, “Rahul”);
owners.zip(houseNumbers); // (Ram:123), (Raj:456), (Rahul:789)</span>
It is also important to note that the length of the lists need not be equal.
The function zip
has many uses like getting the Scalar Product.
Select & Reject
select
and reject
are nothing but filters
. Both of them will accept a predicate. The select
select only those are true
. The reject
select only those are are returning false
.
MutableList<Integer> evenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
.select(i -> i % 2 == 0);
// 0, 2, 4, 6, 8
MutableList<Integer> oddNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
.reject(i -> i % 2 == 0);
// 1, 3, 5, 7, 9</span>
Note you can also do rejectWith and selectWith with a predicate function.
Partition
A PartitionMutableCollection is the result of splitting a mutable collection into two mutable collections based on a Predicate. — Eclipse Collections
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(firstTenNumbers.partition(i -> i % 2 == 0).getSelected()); // 0, 2, 4, 6, 8</span>
The partition
accepts the predicate and will split the list based on the predicate.
Note you can also do partitionWith.
GroupBy
Sometimes we will need to group the elements together, we can use groupBy
for this. The groupBy
will accept the predicate function and groups the element based on the predicate’s return value.
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(firstTenNumbers.groupBy(i -> i % 2 == 0 ? “even” : “odd”));
// {even=[0, 2, 4, 6, 8], odd=[1, 3, 5, 7, 9]}</span>
Collect
The collect
is more or less analogous to map
. It takes a function. Then applies the function on all the values of the list and returns a new list with the updated values.
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(firstTenNumbers.collect(i -> i + 1));
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]</span>
We can even do
flatCollect
.
Distinct
Distinct
as the name implies collect the distinct
values in the array.
MutableList<Integer> distinctValueList = Lists.mutable.with(1, 1, 2, 3, 4).distinct();
// [1, 2, 3, 4]</span>
AnySatisfy, AllSatisfy, and NoneSatisfy
The any|all|noneSatisfy
makes it easy to check and also it is evaluated lazily. For example
MutableList<Character> gradeList = Lists.mutable.with(‘A’, ‘A’, ‘F’, ‘B’);
Boolean isPass = gradeList.allSatisfy(c -> c != ‘F’); // False
Boolean isFail = gradeList.anySatisfy(c -> c == ‘F’); // True
Boolean isPass = gradeList.noneSatisfy(c -> c == ‘F’); // False</span>
Max, Min and SumOfInt
As the name implies they get the maximum, minimum and sumOfInt of the values in the list provided.
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
System.out.println(firstTenNumbers.min()); // 0
System.out.println(firstTenNumbers.max()); // 9
System.out.println(firstTenNumbers.sumOfInt(i -> i)); // 45</span>
There is a lot of other APIs available, check out the full list here).
We will continue with even more in-depth tutorial about Eclipse Collections
.
If you like this article, please leave a like or a comment. :heart:
If you feel there is something wrong / missing in the article feel free to comment :)
You can follow me on Twitter.