O que é Lambda em Kotlin?
Uma lambda é uma função anônima — uma função sem nome que pode ser tratada como valor. Você pode armazená-la em variáveis, passá-la como argumento ou retorná-la de outra função. Lambdas são a base da programação funcional em Kotlin.
A sintaxe é simples: tudo fica entre chaves {}, com os parâmetros antes da seta -> é o corpo depois.
Sintaxe básica
val saudacao = { nome: String -> "Olá, $nome!" }
fun main() {
println(saudacao("Karina")) // Olá, Karina!
}
Lambda como argumento
O uso mais comum de lambdas é como argumento de funções, especialmente com coleções:
fun main() {
val numeros = listOf(1, 2, 3, 4, 5, 6)
val pares = numeros.filter { it % 2 == 0 }
println(pares) // [2, 4, 6]
val dobrados = numeros.map { it * 2 }
println(dobrados) // [2, 4, 6, 8, 10, 12]
}
Quando a lambda tem um único parâmetro, você pode usar it em vez de declarar o nome.
Trailing lambda
Se o último parâmetro de uma função é uma lambda, você pode escrevê-la fora dos parênteses:
val nomes = listOf("Ana", "Bruno", "Carla")
// Essas duas formas são equivalentes:
nomes.forEach({ println(it) })
nomes.forEach { println(it) } // Mais idiomático
Essa convenção deixa o código mais limpo e é usada em toda parte no Kotlin.
Lambda com múltiplos parâmetros
val soma = { a: Int, b: Int -> a + b }
println(soma(3, 7)) // 10
val nomes = mapOf("BR" to "Brasil", "PT" to "Portugal")
nomes.forEach { (codigo, pais) ->
println("$codigo -> $pais")
}
Lambda com receiver
Kotlin suporta lambdas com receiver, que são a base das DSLs:
fun construirTexto(bloco: StringBuilder.() -> Unit): String {
val sb = StringBuilder()
sb.bloco()
return sb.toString()
}
fun main() {
val texto = construirTexto {
append("Kotlin ")
append("Brasil!")
}
println(texto) // Kotlin Brasil!
}
Captura de variáveis (closure)
Lambdas em Kotlin podem acessar e modificar variáveis do escopo externo, formando o que se chama de closure:
fun criarContador(): () -> Int {
var contagem = 0
return {
contagem++
contagem
}
}
fun main() {
val contador = criarContador()
println(contador()) // 1
println(contador()) // 2
println(contador()) // 3
}
Diferente de Java, onde variáveis capturadas devem ser efetivamente finais, Kotlin permite que lambdas modifiquem variáveis var do escopo externo. Isso é possível porque o compilador encapsula a variável em um objeto wrapper.
Lambda vs função anônima
Kotlin também oferece funções anônimas, que são semelhantes a lambdas mas com sintaxe diferente e comportamento de return distinto:
fun main() {
val numeros = listOf(1, 2, 3, 4, 5)
// Lambda: "return" faz non-local return (se inline)
numeros.forEach {
if (it == 3) return@forEach // Label necessario para sair só do lambda
println(it)
}
// Função anônima: "return" retorna da funcao anônima
numeros.forEach(fun(numero) {
if (numero == 3) return // Retorna apenas desta funcao anônima
println(numero)
})
}
A principal diferença prática: em lambdas, return sem label retorna da função envolvente (se inline). Em funções anônimas, return sempre retorna da própria função anônima.
SAM conversion
Kotlin converte lambdas automaticamente para interfaces Java com um único método abstrato (SAM - Single Abstract Method):
// Interface Java funcional
// public interface OnClickListener { void onClick(View view); }
// Em vez de criar uma classe anônima:
button.setOnClickListener { view ->
println("Botão clicado!")
}
Para interfaces Kotlin, a conversão SAM funciona quando a interface é declarada com fun interface:
fun interface Transformador<T> {
fun transformar(valor: T): T
}
fun aplicar(valor: Int, transformador: Transformador<Int>): Int {
return transformador.transformar(valor)
}
fun main() {
// SAM conversion: lambda no lugar da interface
val resultado = aplicar(5) { it * 3 }
println(resultado) // 15
}
Casos de Uso no Mundo Real
- Processamento de coleções: lambdas são usadas em praticamente toda operação com listas, maps e sets no Kotlin —
filter,map,reduce,groupBy,sortedBye dezenas de outros operadores recebem lambdas. - Callbacks em aplicações Android: listeners de clique, observadores de LiveData e callbacks de animação são substituídos por lambdas concisas no lugar de classes anônimas verbosas do Java.
- Configuração de objetos com scope functions:
apply { },also { }elet { }usam lambdas para configurar objetos de forma fluente e legível. - DSLs type-safe: lambdas com receiver permitem criar APIs como o HTML DSL do Kotlin (
html { body { p { +"texto" } } }) e as definições de rotas do Ktor.
Boas Práticas
- Use
itapenas quando a lambda é curta e o significado do parâmetro é óbvio. Em lambdas mais longas, dê um nome descritivo ao parâmetro. - Prefira trailing lambda syntax quando a lambda é o último ou único argumento. Isso é o padrão idiomático em Kotlin.
- Evite lambdas com mais de 5-7 linhas. Se a lógica é complexa, extraia para uma função nomeada e passe como referência com
::. - Use destructuring declarations em lambdas quando trabalhar com pares ou data classes:
map.forEach { (chave, valor) -> ... }. - Prefira
fun interfaceem Kotlin quando precisar de SAM conversion para interfaces Kotlin, em vez de usar tipos de função diretamente.
Erros Comuns
- Confundir
returnem lambda e em função anônima: em lambdas inline,returnsai da função envolvente. Usereturn@nomeDaFuncaopara retornar apenas da lambda. Em funções anônimas,returnsempre retorna da função anônima. - Usar
item lambdas aninhadas: quando há lambdas dentro de lambdas,itse refere ao parâmetro da lambda mais interna. Isso causa confusão. Nomeie os parâmetros explicitamente. - Capturar variáveis mutáveis inadvertidamente: lambdas que capturam variáveis
varpodem gerar bugs quando executadas de forma assíncrona, pois o valor da variável pode mudar entre a criação da lambda e sua execução. - Esquecer que lambdas criam objetos: cada lambda não-inline cria um objeto na JVM. Em loops de alta frequência, isso pode causar pressão no garbage collector. Use
inlinena função receptora para evitar. - Não aproveitar a desestruturação: escrever
{ par -> par.first }em vez de{ (primeiro, _) -> primeiro }torna o código menos legível quando se trabalha com pares ou data classes.
Perguntas Frequentes
Qual a diferença entre lambda e higher-order function? Uma lambda é uma função anônima que pode ser tratada como valor. Uma higher-order function é uma função que recebe ou retorna outras funções (incluindo lambdas). São conceitos complementares.
Lambdas afetam a performance? Sem o modificador inline na função receptora, cada lambda cria um objeto Function na JVM. Para a maioria dos casos, o impacto é desprezível. Em hot paths, use funções inline para eliminar essa alocação.
Posso usar lambdas com coroutines? Sim. Lambdas suspensas (do tipo suspend () -> T) são usadas extensivamente em coroutines. Funções como launch, async e withContext recebem lambdas suspensas como parâmetro.
Quando devo usar função anônima em vez de lambda? Use função anônima quando precisar de um return que retorne apenas da própria função e não da função envolvente, ou quando quiser declarar o tipo de retorno explicitamente. Na maioria dos casos, lambdas são a escolha preferida.
Termos Relacionados
- Higher-Order Function — funções que recebem ou retornam lambdas
- Fun — palavra-chave para declarar funções nomeadas, em contraste com lambdas (anônimas)
- Inline — modificador que elimina o overhead de alocação de objetos para lambdas
- Flow — API de streams assíncronos que utiliza lambdas em seus operadores
Lambdas estão por toda parte no Kotlin. Dominar essa sintaxe é essencial pra escrever código idiomático e produtivo.