Lambda è una funzione anonima rappresentata come espressione compatta { argomenti -> corpo }. In Kotlin, le lambda sono il modo principale per passare comportamenti alle funzioni di ordine superiore, fornendo una sintassi concisa senza dover dichiarare una funzione separata. Secondo la documentazione di Kotlin (2026), oltre il 70% delle funzioni di ordine superiore nei progetti tipici vengono chiamate con lambda. Lambda consente di scrivere codice in stile funzionale con il minimo rumore sintattico.
Punti chiave
Lambda (espressione lambda) è una funzione anonima definita come espressione anziché come dichiarazione. Il termine deriva dal lambda-calcolo di Alonzo Church (1936). In programmazione, una lambda è un blocco di codice che può essere passato come valore, memorizzato in una variabile e chiamato successivamente. In Kotlin, una lambda è sempre racchiusa tra parentesi graffe { }, con gli argomenti separati dal corpo dalla freccia ->.
Una lambda si differenzia da una funzione regolare per l'assenza di nome e della parola chiave fun. Ciò consente di dichiarare il comportamento direttamente nel punto di utilizzo, senza ingombrare il codice con dichiarazioni aggiuntive. Il compilatore Kotlin deduce i tipi degli argomenti dal contesto, quindi in molti casi i tipi possono essere omessi. Una lambda è zucchero sintattico sul tipo funzionale (T) -> R: ogni lambda ha un tipo funzionale corrispondente.
L'uso principale delle lambda in Kotlin è passarle a funzioni di ordine superiore. La libreria standard usa lambda ovunque: filter { it > 0 }, map { it.uppercase() }, forEach { println(it) }. Le lambda sono utilizzate anche per listener di eventi, callback e configuratori di oggetti tramite apply e run, rendendo il codice più dichiarativo rispetto alle classi anonime.
La forma completa di un'espressione lambda in Kotlin: { argomenti -> corpo_lambda }. Gli argomenti sono elencati separati da virgole, seguiti da una freccia e dal corpo — una o più espressioni. Se il corpo contiene più righe, l'ultima espressione diventa il valore di ritorno. Se una funzione accetta una lambda come ultimo argomento, può essere spostata fuori dalle parentesi di chiamata.
val sum: (Int, Int) -> Int = { a, b -> a + b }
// Tipi dedotti dal contesto
val sumShort = { a: Int, b: Int -> a + b }
// Chiamata lambda
val result = sum(5, 3) // 8
println(result)
La variabile sum è dichiarata con un tipo funzionale esplicito (Int, Int) -> Int e inizializzata con una lambda { a, b -> a + b }. Per sumShort, i tipi sono specificati all'interno della lambda e il tipo della variabile è dedotto. Entrambe le varianti sono equivalenti. Chiamare una lambda non è diverso dal chiamare una funzione regolare — usando la sintassi sum(5, 3). Una lambda senza argomenti si scrive come { body }, con un argomento — { it -> it * 2 } o semplicemente { it * 2 }.
Quando una lambda accetta esattamente un argomento, Kotlin fornisce il nome implicito it. Ciò elimina la necessità di dichiarare l'argomento sul lato sinistro. Lo sviluppatore scrive solo il corpo della lambda, usando it per accedere all'unico parametro. Questa sintassi è particolarmente comoda nelle catene di elaborazione di collezioni, dove it si riferisce all'elemento corrente.
val numbers = listOf(1, 2, 3, 4, 5)
// Nome parametro esplicito
val squaredExplicit = numbers.map { n -> n * n }
// it implicito
val squared = numbers.map { it * it }
// Filtraggio con it
val even = numbers.filter { it % 2 == 0 }
println(squared) // [1, 4, 9, 16, 25]
Nell'esempio, map { it * it } usa it invece di dichiarare n ->. Kotlin assegna automaticamente it per un singolo parametro lambda. Se una lambda accetta due o più argomenti, it non viene creato — tutti i parametri devono essere dichiarati esplicitamente. Per una migliore leggibilità delle lambda annidate, conviene dare nomi significativi ai parametri e usare it solo in predicati brevi di una riga.
Trailing lambda è una caratteristica sintattica di Kotlin che consente di spostare l'ultimo argomento lambda fuori dalle parentesi di chiamata della funzione. Questo fa sì che il codice assomigli a costrutti linguistici integrati. Se la lambda è l'unico argomento, le parentesi possono essere omesse completamente. Questo approccio è attivamente utilizzato nella libreria standard e nei DSL.
// Chiamata standard
thread(block = {
println("Ciao dal thread")
})
// Versione trailing lambda
thread {
println("Ciao dal thread")
}
// repeat con trailing lambda
repeat(3) { index ->
println("Iterazione $index")
}
// esegui con lambda multilinea
val config = run {
val host = "localhost"
val port = 8080
"$host:$port"
}
La funzione thread accetta un Runnable come ultimo argomento. Grazie alla trailing lambda, la lambda può essere passata fuori dalle parentesi, assomigliando visivamente a un blocco di codice. La funzione repeat prende un numero di iterazioni e una lambda con un indice. run è un esempio di funzione di ordine superiore dove una lambda multilinea calcola un valore restituito dall'ultima espressione. Le parentesi intorno a run() possono essere omesse se la lambda è l'unico argomento.
La cattura di variabili (closure) è la capacità di una lambda di accedere a variabili dichiarate nello scope esterno. In Kotlin, una lambda può leggere e modificare variabili var, oltre a leggere variabili val dal contesto circostante. Le variabili catturate vengono memorizzate con la lambda per tutto il suo ciclo di vita, consentendo di creare funzioni con stato.
fun makeCounter(): () -> Int {
var count = 0
return {
count++ // catture count
}
}
fun main() {
val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1
println(counter()) // 2
}
La funzione makeCounter dichiara una variabile locale count e restituisce una lambda { count++ }. Sebbene makeCounter abbia completato l'esecuzione, la lambda restituita mantiene un riferimento a count attraverso la chiusura. Ogni chiamata a counter() incrementa e restituisce il valore corrente. Il meccanismo di closure è alla base del currying, delle fabbriche di funzioni e della memoizzazione. È importante ricordare che la cattura di variabili mutabili può portare a comportamenti imprevisti in esecuzione concorrente.
Domande frequenti
Lambda non supporta return incondizionato — un return senza etichetta restituisce il controllo alla funzione esterna. Per uscire da una lambda, usa return@label, dove label è il nome della funzione di ordine superiore a cui la lambda è stata passata.
Una funzione anonima si scrive come fun(a: Int): Int { return a * 2 } e supporta return senza etichetta. Una lambda { a -> a * 2 } è più corta in sintassi ma richiede return@label per un'uscita anticipata.
Se una lambda non accetta argomenti, la freccia viene omessa: { body() }. Se accetta un argomento ma non lo usa, scrivi { _ -> body() } con un trattino basso per ignorare il parametro.
Sì, ogni lambda passata a una funzione non inline crea un'istanza di una classe anonima. Per le funzioni inline, la lambda viene espansa nel sito di chiamata senza creare un oggetto. Le lambda che non catturano vengono memorizzate nella cache come oggetti singleton.
Return in Kotlin è un operatore di salto che appartiene alla funzione più vicina dichiarata con fun. Una lambda non è una funzione (fun), ma un'espressione. Pertanto, un return all'interno di una lambda senza etichetta viene trattato come un ritorno dalla funzione esterna circostante.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche