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]