Immutable lists in Eclipse Collections

Lists are by far among most common data structures, used in Java programming. In a computer science, list is a finite sequence of elements, where each element has it position (index), which allows to access it. The common list implementation in Java is an array based list — the collection, which stores entities in a backed array. While vanilla Java permits to work with immutable lists (since Java 9), it is much better experience to use third-party libraries, that are built using functional programming concepts to handle operations with immutable data structures.

Eclipse Collections library have an extensive support for both mutable and immutable collections, yet, throughout this guide we will concentrate entirely on immutable lists.

Create immutable lists

Eclipse Collections permits us to create both mutable and immutable collections, although in this series we focus only on immutable data structures. An another important thing to mention here is that Eclipse Collections distinguishes between primitive collections and object collections (you may remember, that Java collections use wrapper objects to store primitive elements). Primitive collections store elements with arrays of primitives (e.g. ), rather , as it is done in Java.

In order to create new immutable lists we use factory methods and there are two options:

  • = accepts a sequence of elements to populate a list
  • = create an empty list

For primitive lists we use the corresponding object – for example, to create a list that holds integer values, use pattern. Take a look on the code snippet below, which demonstrates a creation of immutable lists in Eclipse Collections:

Besides this, the object can be created from the Java list. To do it, use the static factory method , which accepts any Java iterable as an argument. Consider the following example:

Finally, you can utilize a Java stream as a source of an immutable list. To demonstrate this, let me use to generate a sequence of numbers from 1 to 100 and create the from that stream:

The last note I would like to make in this section, is that in the last example we used helper methods and to get extremes of the range, rather than using AssertJ to do it. Object lists in Eclipse Collections do implement interface, however, primitive lists have interface as the root. This contract does not implement the iterable and in this regard, does not have same functionality.

After we have obtained instances of immutable lists, let observe how to perform common list operations.

Add and remove entities

Array lists use a backed array to store their elements, so addition and removal take place in that underlaying data structure. An array has a fixed size, but in array-based lists it can shrink in order to accommodate entities. From the other side, we concentrate on immutable collections — these collections cannot be modified. From the technical point of view, this means, that add/remove operations return a new list, rather modify an existing one.

Personally, I found the Eclipse Collections naming convention less confusing, than Vavr. It uses methods and , which are used to add elements and remove elements respectively. Their names tell us that they actually create a new list, that contain a given element or create a new list, that does not contain a given element.

Add elements

As we have seen in the previous section, addition means a creation of a new list, which contains all elements from the original collection, plus the given element(s).

You can add a single element or concate an original collection with another one. This means, that there are two main approaches to add elements in Eclipse Collections:

  • = returns a copy of the original collection with an appended new element
  • = returns a copy of original collection with appended elements from the iterable

Let take a look on the practical examples. Consider this code snippet:

Note, that insertion operations do actually create new lists, that can be proven by the fact, that original lists ( and respectively) do not change their size or include new elements.

Remove elements

An opposite functionality to an insertion as a deletion of entities from the collection. Again, because we work with immutable data structures, these methods technically return new lists, rather than modify originals.

Like with the previous case, there are two ways to do that:

  • = returns a copy of the original list, where the element is removed
  • = similar to the previous one, but this method removes all elements, that are contained in the iterable

Let take a primitive list in this example. Both primitive and object data structures in Eclipse Collections offer this functionality. Look on this code:

Likewise, we can test an immutability by checking, if the original list does contain 5, however the does not.


Java lists do not have built-in filtering functionality, so we have to utilize streams for that. In the contrary, Eclipse Collections supplies two approaches to filter elements — and . Due to the immutable nature, they filter the original list and return a new copy with/without entities, based on a logical condition (predicate).

The difference between these two approaches is following:

  • returns True if the element matches the predicate and it keeps that element in a new list
  • returns False if the eleemnt matches the condition and it copies it to results

From the first glance it may seen sophisticated, however it provides a great code reusability — you can utilize same predicate and filter elements that match it or do not. With plain Java you have to write different conditions! It is better to evaluate it on a practical example. Imagine, that you write an utility, which takes a list of students with GPA (Grade Point Average) and filters students that have a good GPA (GPA > 4.0) and students that do not have good scores (less than 4.0). In Eclipse Collections you just need to create a predicate once and then you can reuse it:

This one-liner takes a object and validates, that the GPA value is bigger that the supplied value . Now, you can use this single predicate for both situations:

  • = will return students that have GPA > 4.0
  • = will return only objects that return False for the given logical condition, e.g. students with GPA less than 4.0!

Take a look on the code snippet below:

You can note, that I used two versions and . The first option takes a predicate, while the later one allows to supply parameters (like ). This provides a better level of code reusability.

Search for the element

In Java programming, to search means to find an index of the matching element or return -1 if the element is not presented in a collection. Obviously, this can answer on a question “Does a collection have an element?”, yet it requires developers to posses that element first. In real life, the search operation is used to query the collection for the element, that matches some condition. Consider, how it is performed when you search for data in a database.

Eclipse Collections bring detect operations to search for data in a collection. As these functions accept predicates, they can be employed to implement a correct repository pattern (the one, which takes criteria conditions).

Comparable to other methods, that we review here, the operation also have several versions:

  • = the basic form, that accepts a logical condition (predicate) and returns a first matching element
  • = this version allows to pass additional argument to a predicate and in this way to reuse code

An important thing to mention here is that the returns first matching element. In the case, when it could not find any element, that matches a predicate, the method returns value. The downside, is that you need to perform an explicit null checking, that could be overcomed if Eclipse Collections would use a concept of Optional. The alternative solution is to provide a default value, that can be obtained using the supplier function, which is called, if no element in the collection does satisfy a predicate condition.

Let have an example to observe how to search for an element using Eclipse Collections immutable lists. Imagine, that we have a list of cities with their population and would like to search for the first city, that has a population (or overcome it), specified by a predicate. Take a look on the code snippet below:

Please note, that for the query, we can’t find in a list a city with population over 1 000 000 people. In that case, the method returns , which may require us to have a manual null checking. This violates principles of functional programming, as we may need to have imperative code snippet to check that (although, we can use , yet it can be considered a bit ugly code style too). In this situation, however we can pass a supplier function, that can be used to generate a default value.

Group elements

This is a quite common task to allocate elements into groups based on some criteria. From a technical point of view, the result is a map, where key is a criteria and a value is a list of values, that satisfy this condition.

Consider an accounting application, where you need to group invoices by customer or by issued date. Java implements this functionality as part of Stream API. In Eclipse Collections framework it can be performed using method, that accepts an aggregator function, which describes a condition to group elements. First, let start with group by customer name. For an example model, customer is just a plain string, so we can do it like this:

We can pass a method reference as an argument for the method. An another case is to group invoices by month. The issued date is represented by a LocalDate instance. So we may write an aggregator function, which get a month of an invoice’s issued date as a grouping criteria. Consider the following code snippet below:

As you can see, mutable collections make very straightforward to aggregate elements into groups, based on the specified criteria. Here we obtain a map result. It is also a common requirement to collect elements into an another collection — we will review it in the next section.


Often, developers need to gather (collect) elements of one list into another. Let quickly return to the GPA example. There we have a list of students, where each model takes two fields (name and GPA). Suppose, that we want to get some GPA statistics for our class, like the lowest, the highest and the average grade. We can do it with the original collection – yet, that will be much more simple to get just a list of GPAs and manipulate double values.

In order to achieve this goal, we can collect GPA values into a new primitive list using the functionality. There is a built-in method, which gathers elements of the list into an immutable list of double primitives.

We need to pass a double function, which basically maps a to a double value. After executing this code, we will get simple statistics for the class:


An another common scenario is to validate, that elements of a sequence satisfy a logical condition. We may need to check that either all elements, either some elements, either none of elements are valid based on a some predicate If you are familiar with Java streams, you remember, that there are three methods — , and . Eclipse Collections framework has three same methods:

The principle of usage is similar to how it is done in plain Java — all we need is a predicate. Let take a list of integers in order to assert the values as even numbers. We can take two scenarios in this example:

  1. Check whenever all numbers are even (using method)
  2. Check if at least one number is even (using )

All these methods return a boolean value.


Out of the box, Java includes an array list implementation as a part of Java Collections Framework. Yet it includes a functionality for common needs, developers may found it insufficient, due to mutability or a weak support of functional API (you need to work with streams for that). Good and accepted by community alternatives include Vavr and Eclipse Collections. In this post we observed most common use cases for Eclipse Collections lists and how to deal with immutable array lists in functional way.

I pay my bills by telling computers what to do