Lambda Expressions
## Learning Objectives
- Understand lambda syntax
- Work with higher-order functions
- Use standard library lambdas
- Master function references
- Learn about inline functions
## Lambda Syntax
### Basic Lambda
```kotlin
fun main() {
// Lambda expression
val sum = { a: Int, b: Int -> a + b }
println(sum(3, 4)) // 7
}
```
### Lambda Expression Syntax
```text
{ parameters -> body }
```
```kotlin
fun main() {
// Multiple parameters
val multiply = { a: Int, b: Int -> a * b }
println(multiply(3, 4)) // 12
// Single parameter - use `it`
val double = { x: Int -> x * 2 }
val double2: (Int) -> Int = { it * 2 }
println(double(5)) // 10
println(double2(5)) // 10
// No parameters
val greet = { -> println("Hello!") }
greet() // Hello!
// Unit return
val printAndReturn = { x: Int ->
println("Value: $x")
}
}
```
### Type Annotations
```kotlin
fun main() {
// Explicit type
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Nullable function type
var maybePrint: ((Int) -> Unit)? = null
maybePrint = { x -> println(x) }
maybePrint?.invoke(42)
}
```
## Higher-Order Functions
A higher-order function takes functions as parameters or returns a function:
```kotlin
// Function as parameter
fun operation(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
fun main() {
val result = operation(10, 5) { x, y -> x + y }
println(result) // 15
val difference = operation(10, 5) { x, y -> x - y }
println(difference) // 5
}
```
### Function Return Type
```kotlin
fun multiplier(factor: Int): (Int) -> Int {
return { x -> x * factor }
}
fun main() {
val double = multiplier(2)
val triple = multiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
}
```
## Standard Library Lambdas
### with
```kotlin
fun main() {
val person = Person().apply {
name = "Alice"
age = 30
}
// with - call multiple methods on same object
val info = with(person) {
"$name is $age years old"
}
println(info) // Alice is 30 years old
}
class Person {
var name: String = ""
var age: Int = 0
}
```
### apply
```kotlin
fun main() {
val person = Person().apply {
name = "Bob"
age = 25
}
println("${person.name}, ${person.age}") // Bob, 25
}
```
### let
```kotlin
fun main() {
// let - transform and return
val length = "Hello".let {
println("String: $it")
it.length
}
println("Length: $length")
// With null safety
val name: String? = "Alice"
name?.let {
println("Name is $it")
}
}
```
### run
```kotlin
fun main() {
val result = "Hello".run {
println("Running on $this")
this.uppercase()
}
println(result) // HELLO
// With block
val person = Person().run {
name = "Charlie"
age = 35
this
}
println("${person.name}, ${person.age}")
}
```
### also
```kotlin
fun main() {
// also - perform additional actions
val numbers = mutableListOf(1, 2, 3)
.also { println("Created list: $it") }
.also { it.add(4) }
.also { println("Added 4: $it") }
println(numbers) // [1, 2, 3, 4]
}
```
## Function References
### Method Reference
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// Method reference
numbers.forEach(::println)
// Reference to top-level function
numbers.forEach(::printNumber)
// Reference to bound method
val person = Person("Alice")
val printName = person::printInfo
printName()
}
fun printNumber(n: Int) {
print("$n ")
}
class Person(val name: String) {
fun printInfo() {
println("Name: $name")
}
}
```
### Constructor Reference
```kotlin
class Person(val name: String)
fun main() {
// Constructor reference
val factory: (String) -> Person = ::Person
val person = factory("Alice")
println(person.name) // Alice
}
```
### Property Reference
```kotlin
var x = 10
fun main() {
println(::x.get()) // 10
::x.set(20)
println(::x.get()) // 20
// In collections
val strings = listOf("hello", "world")
val lengths = strings.map { it.length }
val lengths2 = strings.map(String::length)
println(lengths) // [5, 5]
println(lengths2) // [5, 5]
}
```
## Inline Functions
`inline` tells compiler to insert function body at call site:
```kotlin
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
return System.currentTimeMillis() - start
}
fun main() {
val time = measureTime {
Thread.sleep(100)
}
println("Took $time ms")
}
```
### noinline and crossinline
```kotlin
// noinline - don't inline a specific parameter
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
inlined()
notInlined()
}
// crossinline - must be called but can't have non-local return
inline fun bar(crossinline f: () -> Unit) {
f() // Must call f
}
```
## Common Standard Library Functions
### map
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
println(doubled) // [2, 4, 6, 8, 10]
val names = listOf("Alice", "Bob", "Charlie")
val upper = names.map { it.uppercase() }
println(upper) // [ALICE, BOB, CHARLIE]
}
```
### filter
```kotlin
fun main() {
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val evens = numbers.filter { it % 2 == 0 }
println(evens) // [2, 4, 6, 8, 10]
val greaterThan5 = numbers.filter { it > 5 }
println(greaterThan5) // [6, 7, 8, 9, 10]
}
```
### sorted
```kotlin
fun main() {
val numbers = listOf(5, 2, 8, 1, 9)
println(numbers.sorted()) // [1, 2, 5, 8, 9]
println(numbers.sortedDescending()) // [9, 8, 5, 2, 1]
val words = listOf("banana", "apple", "cherry")
println(words.sorted()) // [apple, banana, cherry]
}
```
### take and drop
```kotlin
fun main() {
val numbers = (1..10).toList()
println(numbers.take(3)) // [1, 2, 3]
println(numbers.takeLast(3)) // [8, 9, 10]
println(numbers.drop(3)) // [4, 5, 6, 7, 8, 9, 10]
println(numbers.dropLast(3)) // [1, 2, 3, 4, 5, 6, 7]
}
```
## Summary
- Lambdas: `{ parameters -> body }` or `{ it }` for single param
- Higher-order functions accept or return functions
- `with`, `apply`, `let`, `run`, `also` are scope functions
- `::` creates function references
- `inline` inlines function body at call site
- `map`, `filter`, `sorted`, `take`, `drop` are common operations
- Lambdas make code more concise and functional
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →