FLORINA MUNTENESCU: Working with collections is a common task.
And the Kotlin Standard Library offers many great utility
functions.
It also offers two ways of working with containers based
on how they're evaluated--
eagerly with collections and lazily with sequences.
In this video, you'll find out what's
the difference between the two, which one you should use
and when, and what are the performance
implications of each of them.
If you learn something new, like the video
and subscribe to the channel, but only if you think
we've earned it.
[MUSIC PLAYING]
The difference between eager and lazy evaluation
lies in when each transformation on the collection is performed.
So let's say that we have a list of objects of different shapes.
We want to make the shapes yellow,
and then take the first square shape.
Let's start with collections.
The first function we call is map.
A new array list is created.
We iterate through all items of the initial collection,
transform it by copying the original object
and changing the color, then add it to the new list.
Then first is called.
We iterate through each item until the first square
is found.
Collections are eagerly evaluated.
Each operation is performed when it's called
and on the entire collection.
The result of the operation is stored in a new collection.
The transformations on collections
are implemented using inline functions.
So for example, looking at how map is implemented,
we can see that it's an inline function that
creates a new array list.
Now, let's see what happens with sequences.
The first method we need to call is asSequence.
And now, a sequence is created based on the iterator
of the original collection.
Then map is called.
Map is an intermediate operation.
Now, the transformation is added to the list of operations
needed to be performed by the sequence,
but the operation is not performed.
Now, first is called.
This is a terminal operation, so all intermediate operations
are triggered on each element of the collection.
We iterate through the initial collection,
applying map and then first on each of them.
Since the condition from first is satisfied
by the second element of the sequence,
then we no longer need to apply map
on the rest of the elements.
When working with sequences, no intermediate collection
is created.
And since items are evaluated one by one,
map is only performed on some of the inputs.
Let's see the implementation of map.
So this is not an inline function,
because the transformation function
is passed to a transforming sequence
object, which stores it.
Looking further down in the implementation of transforming
sequence, we'll see that when next is called on the sequence
iterator, the transformation stored is also applied.
Independent of whether you're using collections or sequences,
the Kotlin Standard Library offers quite a wide range
of operations for both, like find,
filter, groupBy, and others.
Make sure you check them out before implementing
your own version of these.
Now, let's talk about performance a bit.
Independent of whether you're using
collections or sequences, the order of transformations
matters.
So in our example, actually first
doesn't need to happen after map since it's not the consequence
of the map transformation.
If we reverse the order of our business logic
and called first on the collection,
and then transform the result, then we
only create one new object--
the yellow square.
When using sequences we avoid creating two new objects.
When using collections, we avoid creating an entire new list.
Because terminal operations can finish
processing early and intermediate operations are
evaluated lazily, sequences can, in some cases,
help you avoid doing unnecessary work compared to collections.
So make sure you always check the order
of the transformations and the dependencies between them.
Collection operations use inline functions.
So the bytecode of the operation together
with the bytecode of the lambda passed to it will be inline.
Sequences don't use inline functions.
Therefore, new function objects are created for each operation.
On the other hand, collections create a new list
for every transformation, while sequences just
keep a reference to the transformation functions.
When working with small collections
with one or two operators, these differences
don't have big implications, so working with collections
should be OK.
But when working with large lists,
the intermediate collection equation can become expensive.
In such cases, use sequences.
OK, so let's recap.
Collections eagerly evaluate your data,
while sequences do so lazily.
Depending on the size of your data,
pick the one that fits best--
collections for small lists or sequences for larger ones.
And pay attention to the order of the transformations.
That's all on collections and sequences.
Thanks for watching, and go write better Android apps
with Kotlin.
[MUSIC PLAYING]