When streams were added to Java 8, I wanted to jump on the bandwagon. I read blog posts, watched videos, attended workshops to understand what this was all about. After a while, I became comfortable enough…​ but I was unhappy with the implementation: while streams offer methods with a functional approach, legacy collections do not.

When one wants to use Java capabilities on an existing collection, the later needs to be transformed to a stream, and then back again. For example, the following code filters out some elements from a collection, through a streaming step:

List < String > names = Arrays . asList ( "Joe" , "Jack" , "William" , "Averell" ); List < String > jNames = names . stream () . filter ( name -> name . startsWith ( "J" )) . collect ( Collectors . toList ());

On the other hand, Kotlin collections natively offer functional capabilities:

val names = listOf ( "Joe" , "Jack" , "William" , "Averell" ) val jNames = names . filter { it . startsWith ( "J" ) }

That’s the reason I thought it was a better approach (notice the past tense here). There’s a big catch, though: Kotlin functional functions are not lazily-evaluated, while Java stream’s functions are! This is perfectly fine if the collection contains only a few elements, but it can be a huge issue if there are many elements - or many steps in the processing pipeline.

Yet, Kotlin also provide a lazily-evaluated object: the Stream counterpart is Sequence :

Common functions between collections and sequences Though they share common functions, there’s no shared interface between Kotlin collections and Sequence . Their functions are generated through a macro-like script (see GenerateStandardLib for more details). For example, Sequence functions are defined as extensions in the generated kotlin.sequences._Sequences.kt file.