Lambda: co to jest, składnia i użycie w Kotlin

Autor: IT Sectr Opublikowano: 2026-06-23 Czas czytania: 7 min

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 — funkcja anonimowa w składni { args -> body }, nieposiadająca nazwy
  • Niejawna nazwa it zastępuje jedyny argument lambdy, upraszczając zapis
  • Trailing lambda — przeniesienie ostatniej lambdy poza nawiasy wywołania dla czytelności
  • Przechwytywanie (closure) — lambda może odwoływać się do zmiennych z zewnętrznego zakresu widoczności
  • Typ funkcyjny (T) -> R określa sygnaturę lambdy i jest sprawdzany przez kompilator

Czym jest lambda?

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.

Składnia wyrażeń lambda w Kotlin

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.

kotlin
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 }.

Niejawna nazwa it i pomijanie argumentów

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.

kotlin
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 i wieloliniowe lambdy

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.

kotlin
// 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) w lambdach

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.

kotlin
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

Czy lambda może mieć return?

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ę.

Jaka jest różnica między lambdą a funkcją anonimową?

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.

Jak przekazać lambdę jako argument bez strzałki?

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.

Czy lambda zawsze tworzy nowy obiekt?

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.

Dlaczego w lambdzie nie można użyć return bezpośrednio?

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

  • Lambda — funkcja anonimowa w składni { args -> body }, przekazywana jako wartość do funkcji wyższego rzędu
  • Niejawna nazwa it zastępuje jedyny argument i czyni kod bardziej zwięzłym w krótkich predykatach
  • Trailing lambda przenosi ostatnią lambdę poza nawiasy wywołania dla czytelności jako blok kodu
  • Przechwytywanie (closure) pozwala lambdzie odwoływać się do zmiennych z zewnętrznego kontekstu po zakończeniu funkcji otaczającej
  • Typ funkcyjny (T) -> R określa sygnaturę lambdy z kontrolą na etapie kompilacji
  • Inline-funkcje eliminują tworzenie klas anonimowych dla lambd, zwiększając wydajność w pętlach
  • Wieloliniowe lambdy zwracają wartość ostatniego wyrażenia, obsługując złożone obliczenia bez deklarowania osobnej funkcji

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.

Omów projekt

Przeczytaj również