Lambda — to funkcja anonimowa przedstawiona w formie zwięzłego wyrażenia { argumenty -> ciało }. W Kotlin lambdy są podstawowym sposobem przekazywania zachowania do funkcji wyższego rzędu (higher-order functions), zapewniając zwięzłą składnię bez konieczności deklarowania osobnej funkcji. Według dokumentacji Kotlin (2026), ponad 70% funkcji wyższego rzędu w typowych projektach jest wywoływanych z lambdami. Lambda pozwala pisać kod w stylu funkcyjnym z minimalnym szumem składniowym.
Najważniejsze
Lambda (wyrażenie lambda) — to funkcja anonimowa zdefiniowana w formie wyrażenia, a nie deklaracji. Termin pochodzi od rachunku lambda Alonzo Churcha (1936). W programowaniu lambda reprezentuje blok kodu, który może być przekazany jako wartość, zapisany w zmiennej i wywołany później. W Kotlin lambda jest zawsze ujęta w nawiasy klamrowe { }, argumenty są oddzielone od ciała strzałką ->.
Lambda różni się od zwykłej funkcji brakiem nazwy i słowa kluczowego fun. Pozwala to deklarować zachowanie bezpośrednio w miejscu użycia, nie zaśmiecając kodu dodatkowymi deklaracjami. Kompilator Kotlin wyprowadza typy argumentów z kontekstu, dlatego w wielu przypadkach typy można pominąć. Lambda to syntaktyczny cukier nad typem funkcyjnym (T) -> R: każda lambda ma odpowiadający jej typ funkcyjny.
Głównym zastosowaniem lambd w Kotlin jest przekazywanie do funkcji wyższego rzędu (higher-order functions). Biblioteka standardowa używa lambd wszędzie: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Lambdy są również używane do tworzenia nasłuchiwaczy zdarzeń, callbacków, konfiguratorów obiektów przez apply i run, co czyni kod bardziej deklaratywnym w porównaniu z klasami anonimowymi.
Pełna forma wyrażenia lambda w Kotlin: { argumenty -> ciało_lambdy }. Argumenty są wymieniane po przecinku, następnie strzałka i ciało — jedno lub więcej wyrażeń. Jeśli ciało zawiera wiele wierszy, ostatnie wyrażenie staje się wartością zwracaną. Jeśli funkcja przyjmuje lambdę jako ostatni argument, można ją przenieść poza nawiasy wywołania.
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Typy wywnioskowane z kontekstu
val sumShort = { a: Int, b: Int -> a + b }
// Wywołanie lambdy
val result = sum(5, 3) // 8
println(result)
Zmienna sum została zadeklarowana z jawnym typem funkcyjnym (Int, Int) -> Int i zainicjalizowana lambdą { a, b -> a + b }. Dla sumShort typy zostały określone wewnątrz lambdy, a typ zmiennej został wyprowadzony. Oba warianty są równoważne. Wywołanie lambdy niczym nie różni się od wywołania zwykłej funkcji — używana jest składnia sum(5, 3). Lambdę bez argumentów zapisuje się jako { body }, z jednym argumentem — { it -> it * 2 } lub po prostu { it * 2 }.
Gdy lambda przyjmuje dokładnie jeden argument, Kotlin udostępnia niejawną nazwę it. Eliminuje to konieczność deklarowania argumentu po lewej stronie. Programista pisze tylko ciało lambdy, używając it do dostępu do jedynego parametru. Taka składnia jest szczególnie wygodna w łańcuchach przetwarzania kolekcji, gdzie it oznacza bieżący element.
val numbers = listOf(1, 2, 3, 4, 5)
// Jawna nazwa parametru
val squaredExplicit = numbers.map { n -> n * n }
// Niejawne it
val squared = numbers.map { it * it }
// Filtrowanie z it
val even = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
W przykładzie map { it * it } używamy it zamiast deklaracji n ->. Kotlin automatycznie przypisuje it dla jedynego parametru lambdy. Jeśli lambda przyjmuje dwa lub więcej argumentów, it nie jest tworzone — trzeba zadeklarować wszystkie parametry jawnie. Dla poprawy czytelności zagnieżdżonych lambd warto nadawać parametrom znaczące nazwy, a it używać w krótkich jednowierszowych predykatach.
Trailing lambda (lambda końcowa) — cecha składniowa Kotlin, pozwalająca przenieść ostatni argument-lambdę poza nawiasy okrągłe wywołania funkcji. Sprawia to, że kod przypomina wbudowane konstrukcje językowe. Jeśli lambda jest jedynym argumentem, nawiasy można pominąć całkowicie. Takie podejście jest aktywnie wykorzystywane w bibliotece standardowej i DSL.
// Standardowe wywołanie
thread(block = {
println("Witaj z wątku")
})
// Wersja z trailing lambda
thread {
println("Witaj z wątku")
}
// repeat z trailing lambda
repeat(3) { index ->
println("Iteracja $index")
}
// run z wieloliniową lambdą
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
Funkcja thread przyjmuje Runnable jako ostatni argument. Dzięki trailing lambda można przekazać lambdę poza nawiasami, co wizualnie przypomina blok kodu. Funkcja repeat przyjmuje liczbę iteracji i lambdę z indeksem. run — przykład funkcji wyższego rzędu, gdzie wieloliniowa lambda oblicza wartość zwracaną przez ostatnie wyrażenie. Nawiasy wokół run() można pominąć, jeśli lambda jest jedynym argumentem.
Przechwytywanie zmiennych (closure) — zdolność lambdy do odwoływania się do zmiennych zadeklarowanych w zewnętrznym zakresie widoczności. W Kotlin lambda może czytać i modyfikować zmienne var, a także czytać zmienne val z otaczającego kontekstu. Przechwycone zmienne są przechowywane razem z lambdą przez cały czas jej życia, co pozwala tworzyć funkcje ze stanem.
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // liczba przechwyceń
}
}
fun main() {
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 2
}
Funkcja makeCounter deklaruje lokalną zmienną count i zwraca lambdę { count++ }. Mimo że makeCounter zakończyła działanie, zwrócona lambda zachowuje referencję do count przez domknięcie. Każde wywołanie counter() zwiększa i zwraca bieżącą wartość. Mechanizm closure leży u podstaw curryingu, fabryk funkcji i memoizacji. Należy pamiętać, że przechwytywanie zmiennych mutowalnych może prowadzić do nieoczekiwanego zachowania przy równoległym wykonywaniu.
Często zadawane pytania
Lambda nie obsługuje bezwarunkowego return — return bez etykiety zwraca sterowanie do zewnętrznej funkcji. Aby wyjść z lambdy, użyj return@label, gdzie label to nazwa funkcji wyższego rzędu, do której przekazano lambdę.
Funkcja anonimowa zapisywana jest jako fun(a: Int): Int { return a * 2 } i obsługuje return bez etykiety. Lambda { a -> a * 2 } jest krótsza składniowo, ale wymaga return@label do wczesnego wyjścia.
Jeśli lambda nie przyjmuje argumentów, strzałka jest pomijana: { body() }. Jeśli przyjmuje jeden argument i go nie używa, zamiast strzałki pisze się { _ -> body() } z podkreśleniem ignorującym parametr.
Tak, każda lambda przekazana do funkcji non-inline tworzy instancję klasy anonimowej. Dla funkcji inline lambda jest wstawiana w miejscu wywołania bez tworzenia obiektu. Lambdy nieprzechwytujące (non-capturing) są cache'owane w obiektach singletonowych.
Return w Kotlin to operator skoku należący do najbliższej funkcji z fun. Lambda nie jest funkcją (fun), ale wyrażeniem. Dlatego return wewnątrz lambdy bez etykiety jest traktowany jako powrót z zewnętrznej funkcji otaczającej.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również