O que é Lambda em Kotlin?
Resposta rápida: uma lambda em Kotlin é uma função sem nome declarada entre chaves, com os parâmetros antes do ->: { x: Int -> x * 2 }. Ela é tratada como valor — dá para guardar em variáveis, passar como argumento (é a base de filter, map e forEach) e retornar de outras funções. Quando tem um único parâmetro, você pode referenciá-lo como it sem declarar nada.
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.
Lambda x função anônima x função nomeada
| Situação | Melhor escolha | Por quê |
|---|---|---|
Callback curto de 1 a 3 linhas (filter, map, setOnClickListener) | Lambda | Sintaxe mínima e idiomática |
| Precisa retornar antes do fim do bloco | Função anônima | return sai só da função, sem label |
| Lógica reutilizada em vários lugares | Função nomeada + :: referência | Evita duplicação e facilita testes |
| Configuração fluente de objetos e DSLs | Lambda com receiver | apply { }, buildList { } e afins |
| Corpo com mais de 5–7 linhas | Função nomeada | Extraia e passe como ::funcao |
Regra prática: comece com uma lambda; extraia para função nomeada quando ela crescer ou quando precisar de return controlado.
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.
Como declarar o tipo de uma lambda explicitamente? Use a sintaxe de tipo funcional (parametros) -> retorno. Por exemplo: var operacao: (Int, Int) -> Int = { a, b -> a + b }. Isso é útil em propriedades de classe, parâmetros de API pública e quando a inferência não é suficiente. Uma lambda suspenda usa suspend () -> Unit como tipo.
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.
Próximos Passos
- Tutorial de lambdas em Kotlin — passeio guiado por sintaxe, higher-order functions,
ite function references com exercícios - Collections em Kotlin — veja
filter,map,groupByesortedByem ação, os maiores consumidores de lambdas do dia a dia - Coroutines em Kotlin: tutorial básico — conheça as lambdas suspensas usadas por
launch,asyncewithContext - Higher-Order Function — o conceito que permite passar lambdas como argumentos
- Glossário de Kotlin — explore todos os termos da linguagem, de
vala coroutines
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.