A lambda expression is an anonymous function — a function without a name — written inline. Lambdas are the foundation of Kotlin's collection APIs, callbacks, and Compose event handlers.
Basic syntax
Lambda syntax// Full form: { parameters -> body }
val sum = { a: Int, b: Int -> a + b }
fun main() {
println(sum(3, 5)) // 8
val double = { x: Int -> x * 2 }
println(double(10)) // 20
}
The implicit it parameter
When a lambda has exactly one parameter, you can omit the parameter name and use it:
it keywordfun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val squared = numbers.map { it * it }
val evens = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
println(evens) // [2, 4]
}
Trailing lambda syntax
If the last parameter of a function is a lambda, it can be placed outside the parentheses:
Storing lambda in variableval greet: (String) -> String = { name -> "Hello, $name!" }
fun main() {
println(greet("Nikhil"))
}
SAM conversion
For Java functional interfaces or Kotlin fun interface, a lambda can replace the single abstract method — e.g. button.setOnClickListener { ... } in Android.
2Higher Order Functions
A higher-order function (HOF) either takes one or more functions as parameters, returns a function, or both. This enables flexible, reusable code — the pattern behind map, filter, and custom utilities.
Function as parameter
HOF accepting lambdafun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
fun main() {
val add = calculate(10, 5) { x, y -> x + y }
val multiply = calculate(10, 5) { x, y -> x * y }
println(add) // 15
println(multiply) // 50
}
Function as return value
Returning a functionfun multiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}
fun main() {
val times3 = multiplier(3)
val times5 = multiplier(5)
println(times3(10)) // 30
println(times5(10)) // 50
}
Custom higher-order utility
repeat and applyIffun repeat(times: Int, action: (Int) -> Unit) {
for (i in 0 until times) {
action(i)
}
}
fun <T> List<T>.applyIf(
condition: Boolean,
transform: (List<T>) -> List<T>
): List<T> {
return if (condition) transform(this) else this
}
fun main() {
repeat(3) { i -> println("Iteration $i") }
val nums = listOf(1, 2, 3)
println(nums.applyIf(true) { it.map { n -> n * 2 } })
}
Standard library HOFs
Function
Lambda role
Example
map
Transform element
list.map { it * 2 }
filter
Keep if true
list.filter { it > 0 }
reduce
Combine to one value
list.reduce { a, b -> a + b }
fold
Reduce with initial
list.fold(0) { acc, x -> acc + x }
forEach
Side effect per item
list.forEach { println(it) }
let / run / apply
Scope functions
user?.let { save(it) }
inline functions: Many stdlib HOFs are inline — the compiler inlines the lambda to reduce overhead. See Inline Functions.
3Anonymous Functions
An anonymous function is another way to pass a function literal — using the fun keyword with a body block. Unlike lambdas, anonymous functions support multiple return points with labeled return.
Anonymous function syntax
Anonymous functionfun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// Lambda form
val evensLambda = numbers.filter { it % 2 == 0 }
// Anonymous function form
val evensAnon = numbers.filter(fun(n): Boolean {
return n % 2 == 0
})
println(evensLambda) // [2, 4]
println(evensAnon) // [2, 4]
}
Lambda vs anonymous function
Feature
Lambda
Anonymous function
Syntax
{ x -> x * 2 }
fun(x: Int): Int { return x * 2 }
Return
Last expression is result
return exits the function block
Implicit it
Yes (single param)
No — must name parameters
Return type
Inferred
Can specify explicitly
Typical use
Short callbacks, collections
Complex logic with early return
Non-local return with anonymous function
Early return in anonymous functionfun processNumbers(numbers: List<Int>) {
numbers.forEach(fun(n) {
if (n < 0) return@forEach // return from anonymous function only
println(n)
})
}
fun main() {
processNumbers(listOf(1, -2, 3)) // prints 1, 3
}
When to choose which
Use lambda
Short one-liners: filter { it > 0 }, click listeners, map transforms.
Use anonymous fun
Multi-step logic, explicit return type, or labeled returns from nested HOF.
Labeled return in lambda
In inline HOFs, use return@forEach to return from the lambda only. A bare return in a lambda returns from the enclosing function (non-local return) — only allowed in inline functions.
4Functional Programming Basics
Functional programming (FP) treats computation as evaluation of functions, emphasizes immutability, and avoids changing shared state. Kotlin is multi-paradigm — you can combine OOP with FP patterns.
Core FP concepts in Kotlin
Concept
Meaning
Kotlin example
First-class functions
Functions are values
val f: (Int) -> Int = { it * 2 }
Immutability
Prefer unchanging data
val list = listOf(1, 2, 3)
Pure functions
Same input → same output, no side effects
fun add(a: Int, b: Int) = a + b
Higher-order functions
Functions operating on functions
list.map { it * 2 }
Function composition
Combine small functions
Pipeline: filter → map → reduce
Pure vs impure functions
Pure function// Pure — no side effects, predictable
fun square(n: Int): Int = n * n
// Impure — depends on/modifies external state
var counter = 0
fun increment(): Int {
counter++
return counter
}
Immutable transformation pipeline
FP-style data pipelinedata class Order(val id: Int, val amount: Double, val status: String)
fun main() {
val orders = listOf(
Order(1, 100.0, "PAID"),
Order(2, 50.0, "PENDING"),
Order(3, 200.0, "PAID")
)
val totalPaid = orders
.filter { it.status == "PAID" }
.map { it.amount }
.fold(0.0) { acc, amount -> acc + amount }
println("Total paid: $totalPaid") // 300.0
}
Scope functions — functional style helpers
let, run, apply, also, withdata class User(val name: String, var email: String)
fun main() {
val user = User("Nikhil", "old@mail.com")
user.apply {
email = "new@mail.com"
}
val display = user.let { u ->
"${u.name} <${u.email}>"
}
println(display)
}
Scope function
Object ref
Return value
Typical use
let
it
Lambda result
Null-safe transform
run
this
Lambda result
Configure + compute
apply
this
Object itself
Object initialization
also
it
Object itself
Side effects / logging
with
this
Lambda result
Group calls on object
FP benefits in Android & backend
Fewer bugs
Immutable data and pure functions reduce race conditions and unexpected mutations.
Composable logic
Small functions chain into readable pipelines — filter, map, reduce.
Testability
Pure functions are easy to unit test — no mocks for global state.
Modern Android
Compose, Flow, and coroutines embrace functional reactive patterns.
Practical balance: Kotlin does not require pure FP — use immutable collections and HOFs where they simplify code, and OOP where it models domain entities. Related: Collections, Coroutines.
5Summary Cheatsheet
Topic
Key Takeaway
Lambda Expressions
{ params -> body }; it for single param; trailing lambda