Chapter 9 of 12 ~18 min read

Lambdas & Higher-Order Functions

Kotlin's lambda syntax is more concise than Java. Learn the 5 scope functions and how to write your own higher-order functions.


Lambda Syntax

Java 8+ Lambdas
// Verbose functional interface
Runnable r = () -> System.out.println("Hi");

// With parameters
Comparator<String> comp =
    (a, b) -> a.compareTo(b);

// In stream:
list.stream()
    .filter(s -> s.length() > 3)
    .forEach(s -> System.out.println(s));
Kotlin Lambdas
// Lambda syntax: { params -> body }
val printHi = { println("Hi") }

// With parameters:
val compare = { a: String, b: String ->
    a.compareTo(b)
}

// 'it' shorthand for single parameter:
list.filter { it.length > 3 }
    .forEach { println(it) }

Higher-Order Functions

Functions that accept or return other functions. You've been using them with filter, map, etc.:

Kotlin
// Accept a function as parameter
fun transform(value: Int, action: (Int) -> String): String {
    return action(value)
}

// Call with a lambda:
val result = transform(42) { "Value is $it" }
// "Value is 42"

// Return a function:
fun multiplier(factor: Int): (Int) -> Int {
    return { number -> number * factor }
}
val triple = multiplier(3)
triple(5) // 15

The 5 Scope Functions

Kotlin's scope functions are the most Kotlin-idiomatic code patterns. They replace repetitive assignments and null checks:

FunctionContext objectReturnsBest for
letitLambda resultNull checks, transformations
applythisContext objectObject initialization / builder pattern
runthisLambda resultInitialization + computation
alsoitContext objectSide effects (logging, assertions)
withthisLambda resultGroup operations on an object
Kotlin — scope function examples
// let — transform or null-safe operation
val name: String? = "  Alice  "
val length = name?.let { it.trim().length } // 5

// apply — configure an object, returns the object
val intent = Intent(context, MainActivity::class.java).apply {
    putExtra("KEY", "value")
    flags = Intent.FLAG_ACTIVITY_NEW_TASK
}

// run — execute block and return result
val result = "Hello".run {
    lowercase() + " world"
} // "hello world"

// also — side effect, returns original object
val user = User("Alice", 30)
    .also { println("Created: ${it.name}") }
// user is still User("Alice", 30)

// with — group operations
val sb = StringBuilder()
with(sb) {
    append("Hello")
    append(", ")
    append("World!")
}
println(sb) // Hello, World!