Eclipse Collections - the features your collections need 🎉⚡️👍
Tags: java, datastructures, tutorial, codenewbie
Published: 2019-08-14 09:05:54

> Deny it or not data structures are important. Picking the right one will enormously increase the performance of your program/product/application. 

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 will increase the learning curve of the language, providing too less will lead to cumbersome implementation by the users. So languages have to be very careful in what they provide.

# [Eclipse collections](https://github.com/eclipse/eclipse-collections) provide optimized and efficient implementations of collections in Java. 

Eclipse collections also 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
  - Eager (while optimized)
* provides both `immutable` and `mutable` collections
* provide highly optimized and memory-efficient implementation

## Set things up 

If you are using a `Maven` project include the `eclipse collection` dependencies like below:

```markup
<dependency
    <groupId>org.eclipse.collections</groupId>
    <artifactId>eclipse-collections</artifactId>
    <version>10.0.0</version>
</dependency>
```

If you are using `Gradle` then import it:

```groovy
compile 'org.eclipse.collections:eclipse-collections-api:10.0.0'
compile 'org.eclipse.collections:eclipse-collections:10.0.0'
```

## Ingredients

The Eclipse Collections consists of the following data structures:

1. List
1. Set
1. Map
1. BiMap
1. MultiMap
1. Bag
1. Stack 
1. Pair and others

All those data structures include the following implementations:

1. Mutable
1. Immutable
1. Lazy
1. Parallel
1. Ordered
1. Sorted
1. Fixed 
1. 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](https://github.com/eclipse/eclipse-collections-kata).

Let us start with a `List`.

To instantiate a new mutable list we can do the following:

```java
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```

You can instantiate the list with `of`.

```java
MutableList<Integer> firstTenNumbers = Lists.mutable.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
```


### Reterival

We can retrieve the elements using classic `get(index)` way. The Eclipse Collections also provide a `getFirst()` and `getLast()` method to retrieve the first and the last elements respectively.

```java
firstTenNumbers.get(4);       // 4
firstTenNumbers.getFirst();  // 0
firstTenNumbers.getLast();  // 9
```

In functional paradigm, `take` | `takeWhile` | `drop` | `dropWhile` APIs are awesome because they help to 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` gives back all the elements until the index.

```java
firstTenNumbers.take(3); // 0, 1, 2
firstTenNumbers.drop(3); // 3, 4, 5, 6, 7, 8, 9
```

The functions `drop` and `take` can be specified by the following function:

```java
list.take(n) + list.drop(n) == list
```

### 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. 

```java
firstTenNumbers.takeWhile(i -> i % 2 == 0); // 0
```

The `dropWhile` function will return all the values in the list after which the predicate returns true.

```java
firstTenNumbers.dropWhile(i -> i % 2 == 0); // 1, 2, 3, 4, 5, 6, 7, 8, 9
```

### convertors

Often times, we will 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` and `toImmutable` function respectively.

```java
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
```

We will need to reverse our list and the API provides us with `toReversed` function to achieve the same.

```java
MutableList<T> normalList = Lists.mutable.with(T... args);
normalList.toReversed();
```

The stack data structure is inbuilt in the library. We can convert the `list` into `stack` using `toStack`. 


```java
MutableList<Integer> firstTenNumbers = Lists.mutable.with(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
firstTenNumbers.toStack().pop(4); // 9, 8, 7, 6
```

> 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:

```java
[T], [U] =>  [T, U]
```

```java
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)
```

> 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`.

```java
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
```

```java
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
```

> Note you can also do `rejectWith` and `selectWith`.

### partition

> A PartitionMutableCollection is the result of splitting a mutable collection into two mutable collections based on a Predicate. - Eclipse Collections

```java
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
```

The `partition` will accept 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.

```java
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]}
```

### collect

The `collect` is more or less analogous to `map`. It takes a predicate function. Then applies the function on all the values of the list and returns a new list with the updated values.


```java
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]
```

> We can even do `flatCollect`.

### distinct

`Distinct` as the name implies collect the `distinct` values in the array.

```java
MutableList<Integer> distinctValueList = Lists.mutable.with(1, 1, 2, 3, 4).distinct();
// [1, 2, 3, 4]
```

### anySatisfy, allSatisfy, and noneSatisfy

The `any|all|noneSatisfy` makes it easy to check and also it is evaluated lazily. For example

```java
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
```

### max, min and sumOfInt

As the name implies they get the maximum, minimum and sumOfInt of the values in the list provided.

```java
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
```

There is a lot of other APIs available, check out the full list [here](https://www.eclipse.org/collections/javadoc/10.0.0/overview-summary.html).


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](https://twitter.com/sendilkumarn).