From Eager to Fused to Lazy
An evolution of iteration methods in Eclipse Collections
In the beginning there was Eager
When the first iteration methods were implemented in Eclipse Collections they were all eager. Eager is the default behavior on the collection interfaces and implementations in Eclipse Collections.
When using eager methods with multiple operations in a fluent style, you may create intermediate collections.
The call to select
above will create a MutableList<Integer>
. The call to collect
then creates a MutableList<String>
. The following code shows explicitly the return types of the calls to select
and collect
.
The imperative code for select
and collect
would look as follows.
Optimizing with a Fused method
When we started replacing imperative for
loops with higher level iteration patterns we occasionally saw for
loops that were doing multiple things. These for
loops could be broken down into individual steps like select
and collect
, but it was then clear that there was more temporary garbage being created. This is when we introduced one of the first fused methods named collectIf
. The method collectIf
is a shorter name for selectAndCollect
.
The fused method collectIf
includes both the Predicate
and Function
required to filter and transform the list in one pass.
This is what an imperative for
loop would look like if it was doing a collectIf
operation.
The fused operation collectIf
is as close to the imperative for
loop as you can get only without having the list creation, the for
loop, the if
statement and the call to add
on the collection.
Time to be Lazy
We added the lazy API to Eclipse Collections after the eager and fused API. The lazy API in Eclipse Collections is available via a call to asLazy
. The lazy API will defer execution until a terminal operation is called (like forEach
or toList
). The lazy API in Eclipse Collections returns an Iterable
type named LazyIterable
. Unlike Stream
which was added in Java 8, LazyIterable
can be reused. The following blog has more about LazyIterable
and how it is inexhaustible.
The benefit of the lazy API is that intermediate collections are not created. The calls to asLazy
, select
, and collect
all create LazyIterable
instances that do nothing. The final call to toList
forces execution to happen and creates the target list.
The following code shows the result of each operation.
The following imperative code shows how two Iterables
can be composed together and then iterated using a for
loop to achieve the same result.
Recommendations
Sometimes it is better to use eager, fused or lazy. Here are the rules I recommend with Eclipse Collections.
- Use eager methods for single operations, or if you are working with small collections.
- Use a fused method if it matches exactly to the scenario you have like
collectIf
. - Use lazy if you have more than one operation that would otherwise cause more temporary collections to be created.
I am a Project Lead and Committer for the Eclipse Collections OSS project at the Eclipse Foundation. Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.