Lambda — это анонимная функция, представленная в виде компактного выражения { аргументы -> тело }. В Kotlin лямбды являются основным способом передачи поведения в higher-order functions, обеспечивая лаконичный синтаксис без необходимости объявлять отдельную функцию. По данным документации Kotlin (2026), более 70% higher-order функций в типовых проектах вызываются с лямбдами. Lambda позволяет писать код в функциональном стиле с минимальным синтаксическим шумом.
Главное
Lambda (лямбда-выражение) — это анонимная функция, определённая в виде выражения, а не декларации. Термин происходит от лямбда-исчисления Алонзо Чёрча (1936). В программировании лямбда представляет собой блок кода, который может быть передан как значение, сохранён в переменной и вызван позднее. В Kotlin лямбда всегда заключена в фигурные скобки { }, аргументы отделяются от тела стрелкой ->.
Лямбда отличается от обычной функции отсутствием имени и ключевого слова fun. Это позволяет объявлять поведение непосредственно в точке использования, не загромождая код дополнительными декларациями. Компилятор Kotlin выводит типы аргументов из контекста, поэтому во многих случаях типы можно опустить. Лямбда — это синтаксический сахар над функциональным типом (T) -> R: каждая лямбда имеет соответствующий функциональный тип.
Основное применение лямбд в Kotlin — передача в higher-order functions (функции высшего порядка). Стандартная библиотека использует лямбды повсеместно: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Лямбды также применяются для создания слушателей событий, колбэков, конфигураторов объектов через apply и run, что делает код более декларативным по сравнению с анонимными классами.
Полная форма лямбда-выражения в Kotlin: { аргументы -> тело_лямбды }. Аргументы перечисляются через запятую, затем следует стрелка и тело — одно или несколько выражений. Если тело содержит несколько строк, последнее выражение становится возвращаемым значением. Если функция принимает лямбду последним аргументом, её можно вынести за скобки вызова.
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Types inferred from context
val sumShort = { a: Int, b: Int -> a + b }
// Lambda call
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)
// Explicit parameter name
val squaredExplicit = numbers.map { n -> n * n }
// Implicit it
val squared = numbers.map { it * it }
// Filtering with 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.
// Standard call
thread(block = {
println("Hello from thread")
})
// Trailing lambda version
thread {
println("Hello from thread")
}
// repeat with trailing lambda
repeat(3) { index ->
println("Iteration $index")
}
// run with multiline lambda
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
Функция thread принимает Runnable как последний аргумент. Благодаря trailing lambda можно передать лямбду за скобками, что визуально напоминает блок кода. Функция repeat принимает количество итераций и лямбду с индексом. run — пример higher-order function, где многострочная лямбда вычисляет значение, возвращаемое последним выражением. Скобки вокруг run() можно опустить, если лямбда — единственный аргумент.
Захват переменных (closure) — способность лямбды обращаться к переменным, объявленным во внешней области видимости. В Kotlin лямбда может читать и модифицировать var-переменные, а также читать val-переменные из окружающего контекста. Захваченные переменные хранятся вместе с лямбдой на всём протяжении её жизненного цикла, что позволяет создавать функции с состоянием.
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // captures 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 — имя higher-order function, в которую передана лямбда.
Анонимная функция записывается как 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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также