Sequences for Lazy Evaluation

Simply put, collections are eager and sequences are lazy. Sequences are optimized wrappers around collections intended to improve performance. In this section, we’ll look at what that means and how to decide when to use collections and when to use sequences.

Unlike Java, the methods like filter(), map(), and so on are available in Kotlin directly on collections like List<T>, instead of only on a Stream<T>. The designers of Java made a decision against offering these methods on collections for performance reasons. The designers of Kotlin, on the other hand, decided to lean toward convenience, and they expect us to choose wisely.

Use the internal iterators on collections directly in Kotlin when the collection size is small. For larger collections, use the internal iterators through a sequence. The reason for this is that unlike operations on collections that are evaluated eagerly, the function calls on sequences are evaluated lazily. Laziness defers execution of code to the point where they may be eliminated if unnecessary. That optimization can save time and resources that may otherwise be spent on computations whose results may never be used. And laziness also makes it possible to create infinite sequences that are evaluated on demand. We’ll explore these ideas and discuss their benefits here.

Improve performance with sequences

Let’s revisit the example from the previous section where we obtained the first adult in a given list. We’ll use the same Person class and the people list we created earlier. Using the internal iterators filter(), map(), and first(), we get the name of the first adult in the group. Instead of passing lambdas to filter() and map(), we’ll pass function references. The filter() method takes a reference to an isAdult() function, and the map() method takes a reference to the fetchFirstName() function.

Get hands-on with 1400+ tech skills courses.