Lambda — це анонімна функція, представлена у вигляді компактного виразу { аргументи -> тіло }. У Kotlin лямбди є основним способом передачі поведінки у функції вищого порядку, забезпечуючи лаконічний синтаксис без необхідності оголошувати окрему функцію. Згідно з документацією Kotlin (2026), понад 70% функцій вищого порядку в типових проектах викликаються з лямбдами. Lambda дозволяє писати код у функціональному стилі з мінімальним синтаксичним шумом.
Головне
Lambda (лямбда-вираз) — це анонімна функція, визначена у вигляді виразу, а не декларації. Термін походить від лямбда-числення Алонзо Черча (1936). У програмуванні лямбда являє собою блок коду, який може бути переданий як значення, збережений у змінній і викликаний пізніше. У Kotlin лямбда завжди заключена у фігурні дужки { }, аргументи відділяються від тіла стрілкою ->.
Лямбда відрізняється від звичайної функції відсутністю імені та ключового слова fun. Це дозволяє оголошувати поведінку безпосередньо в точці використання, не захаращуючи код додатковими деклараціями. Компілятор Kotlin виводить типи аргументів із контексту, тому в багатьох випадках типи можна опустити. Лямбда — це синтаксичний цукор над функціональним типом (T) -> R: кожна лямбда має відповідний функціональний тип.
Основне застосування лямбд у Kotlin — передача у функції вищого порядку. Стандартна бібліотека використовує лямбди повсюдно: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Лямбди також застосовуються для створення слухачів подій, колбеків, конфігураторів об'єктів через apply і run, що робить код більш декларативним порівняно з анонімними класами.
Повна форма лямбда-виразу в Kotlin: { аргументи -> тіло_лямбди }. Аргументи перераховуються через кому, потім слідує стрілка і тіло — один або кілька виразів. Якщо тіло містить кілька рядків, останній вираз стає значенням, що повертається. Якщо функція приймає лямбду останнім аргументом, її можна винести за дужки виклику.
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Типи, виведені з контексту
val sumShort = { a: Int, b: Int -> a + b }
// Виклик Lambda
val result = sum(5, 3) // 8
println(result)
Змінна sum оголошена з явним функціональним типом (Int, Int) -> Int та ініціалізована лямбдою { a, b -> a + b }. Для sumShort типи вказані всередині лямбди, а тип змінної виведений. Обидва варіанти еквівалентні. Виклик лямбди нічим не відрізняється від виклику звичайної функції — використовується синтаксис sum(5, 3). Лямбду без аргументів записують як { body }, з одним аргументом — { it -> it * 2 } або просто { it * 2 }.
Коли лямбда приймає рівно один аргумент, Kotlin надає неявне ім'я it. Це усуває необхідність оголошувати аргумент у лівій частині. Розробник пише лише тіло лямбди, використовуючи it для доступу до єдиного параметра. Такий синтаксис особливо зручний у ланцюжках обробки колекцій, де it позначає поточний елемент.
val numbers = listOf(1, 2, 3, 4, 5)
// Явне ім'я параметра
val squaredExplicit = numbers.map { n -> n * n }
// Неявне it
val squared = numbers.map { it * it }
// Фільтрація з it
val even = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
У прикладі map { it * it } використовує it замість оголошення n ->. Kotlin автоматично призначає it для єдиного параметра лямбди. Якщо лямбда приймає два або більше аргументів, it не створюється — потрібно оголошувати всі параметри явно. Для покращення читабельності вкладених лямбд варто давати параметрам осмислені імена, а it використовувати в коротких однорядкових предикатах.
Trailing lambda — синтаксична особливість Kotlin, яка дозволяє винести останній аргумент-лямбду за круглі дужки виклику функції. Це робить код схожим на вбудовані мовні конструкції. Якщо лямбда є єдиним аргументом, дужки можна опустити повністю. Такий підхід активно використовується в стандартній бібліотеці та DSL.
// Стандартний виклик
thread(block = {
println("Привіт із потоку")
})
// Версія trailing lambda
thread {
println("Привіт із потоку")
}
// repeat з trailing lambda
repeat(3) { index ->
println("Ітерація $index")
}
// run з багаторядковою лямбдою
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
Функція thread приймає Runnable як останній аргумент. Завдяки trailing lambda можна передати лямбду за дужками, що візуально нагадує блок коду. Функція repeat приймає кількість ітерацій та лямбду з індексом. run — приклад функції вищого порядку, де багаторядкова лямбда обчислює значення, що повертається останнім виразом. Дужки навколо run() можна опустити, якщо лямбда — єдиний аргумент.
Захоплення змінних (closure) — здатність лямбди звертатися до змінних, оголошених у зовнішній області видимості. У Kotlin лямбда може читати та модифікувати var-змінні, а також читати val-змінні з навколишнього контексту. Захоплені змінні зберігаються разом з лямбдою протягом усього її життєвого циклу, що дозволяє створювати функції зі станом.
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // кількість захоплень
}
}
fun main() {
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 2
}
Функція makeCounter оголошує локальну змінну count і повертає лямбду { count++ }. Незважаючи на те що makeCounter завершила роботу, повернена лямбда зберігає посилання на count через замикання. Кожен виклик counter() збільшує та повертає поточне значення. Механізм closure лежить в основі каррінгу, фабрик функцій та мемоізації. Важливо пам'ятати, що захоплення змінних змінних може призводити до неочікуваної поведінки при паралельному виконанні.
Поширені запитання
Лямбда не підтримує безумовний return — return без мітки повертає управління із зовнішньої функції. Для виходу з лямбди використовуйте return@label, де label — ім'я функції вищого порядку, в яку передана лямбда.
Анонімна функція записується як fun(a: Int): Int { return a * 2 } і підтримує return без мітки. Лямбда { a -> a * 2 } коротша за синтаксисом, але вимагає return@label для раннього виходу.
Якщо лямбда не приймає аргументів, стрілка опускається: { body() }. Якщо приймає один аргумент і не використовує його, замість стрілки пишуть { _ -> body() } з підкресленням для ігнорування параметра.
Так, кожна лямбда, передана в non-inline функцію, створює екземпляр анонімного класу. Для inline-функцій лямбда вбудовується на сайт виклику без об'єкта. Non-capturing лямбди кешуються в singleton-об'єкти.
Return у Kotlin — це оператор переходу, що належить найближчій функції з fun. Лямбда — не функція (fun), а вираз. Тому return всередині лямбди без мітки розглядається як повернення із зовнішньої об'ємлючої функції.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також