Что такое lambda-выражения в Kotlin?

Lambda-выражения в Kotlin — это анонимные функции, которые можно передавать как значения, сохранять в переменные, вызывать напрямую или передавать как аргументы в другие функции. Они являются частью функционального программирования и играют ключевую роль при работе с коллекциями, обработке событий, построении DSL и других сценариях.

Синтаксис lambda-выражения

Общий вид:

val lambdaName: Type = { parameters -> body }

Примеры:

val sum = { a: Int, b: Int -> a + b }
val greet = { println("Hello!") }

Lambda можно вызвать, как обычную функцию:

println(sum(3, 5)) // 8
greet() // Hello!

Тип lambda-выражения

Тип lambda зависит от количества параметров и возвращаемого значения. Kotlin использует функциональные интерфейсы вида () -> Unit, (Int) -> String, (String, Int) -> Boolean и т.д.

val multiply: (Int, Int) -> Int = { x, y -> x \* y }
val sayHi: () -> Unit = { println("Hi") }

Использование в функциях высшего порядка

Функции высшего порядка — это функции, принимающие другие функции в качестве параметров или возвращающие их. Lambda особенно часто используется в таких случаях:

fun operate(x: Int, y: Int, op: (Int, Int) -> Int): Int {
return op(x, y)
}
val result = operate(4, 5) { a, b -> a + b } // 9

Специальный параметр it

Если у lambda-выражения один параметр, его можно не объявлять явно — Kotlin использует неявное имя it.

listOf(1, 2, 3).forEach { println(it) }

В этом примере it — это текущий элемент списка.

Возврат значений из lambda

Последнее выражение в lambda — это возвращаемое значение:

val square = { x: Int -> x \* x }
println(square(4)) // 16

Оператор return в lambda по умолчанию возвращает из окружающей функции только при использовании inline, иначе запрещён.

Для явного возврата из lambda в сложных случаях используют метки:

fun test() {
listOf(1, 2, 3).forEach label@{
if (it == 2) return@label
println(it)
}
}

Сокращённый синтаксис

Многие стандартные функции (например, filter, map, forEach, let) принимают lambda как аргумент и позволяют писать компактный код:

val names = listOf("Alice", "Bob", "Charlie")
val longNames = names.filter { it.length > 3 }

Lambda как объект: Function интерфейсы

Lambda — это экземпляры интерфейсов FunctionN, где N — количество параметров.

Примеры:

  • { -> ... } → Function0<R>

  • { a -> ... } → Function1<T, R>

  • { a, b -> ... } → Function2<T1, T2, R>

Lambda также можно передавать и возвращать как объекты:

fun makeMultiplier(factor: Int): (Int) -> Int {
return { it \* factor }
}

Замыкания (Closures)

Lambda в Kotlin замыкает (захватывает) переменные из внешнего контекста:

fun makeCounter(): () -> Int {
var count = 0
return {
count += 1
count
}
}
val counter = makeCounter()
println(counter()) // 1
println(counter()) // 2

count — это захваченная переменная, живущая внутри lambda.

Lambda как аргумент вне скобок

Если последним аргументом функции является lambda, её можно вынести за круглые скобки:

fun doWork(task: () -> Unit) {
task()
}
doWork {
println("Working…")
}

Если lambda — единственный аргумент, скобки можно опустить:

run {
println("Inside run block")
}

Анонимные функции (fun) vs lambda

Kotlin также позволяет определять анонимные функции с использованием ключевого слова fun. Это похоже на lambda, но с явным указанием возвращаемого типа и return.

val divide = fun(a: Int, b: Int): Int {
if (b == 0) return 0
return a / b
}

Ключевое отличие — поведение return: в анонимной функции return работает как ожидается, а в lambda может требовать метку или inline-контекст.

Примеры использования в стандартной библиотеке Kotlin

  • map, filter, fold, reduce, groupBy, sortedBy

  • let, apply, run, also, with

  • Обработка событий, DSL, builder-паттерны

Пример:

val result = listOf(1, 2, 3)
.map { it \* 2 }
.filter { it > 3 }

Lambda-выражения — фундаментальный инструмент в Kotlin, позволяющий писать краткий, выразительный и гибкий код. Их мощь особенно раскрывается при использовании коллекций, конструировании DSL, реализации паттернов и написании функций высшего порядка.