Uma higher-order function é uma função que recebe outra função como parâmetro ou retorna uma função como resultado. Em Kotlin, as funções são cidadãos de primeira classe: podem ser armazenadas em variáveis, passadas como argumentos e retornadas. De acordo com a documentação do Kotlin (2026), as higher-order functions reduzem a duplicação de código em média 30% em comparação com abordagens imperativas. Higher-order function é um conceito fundamental do estilo funcional no desenvolvimento moderno.
Pontos principais
Higher-order function é uma função que possui pelo menos uma de duas características: receber outra função como argumento ou retornar uma função como resultado. Em matemática, essas funções são chamadas de funcionais ou operadores. Na programação, elas apareceram em Lisp em 1958 e se tornaram parte obrigatória de todas as linguagens modernas — JavaScript, Python, Swift, Kotlin, Scala e Haskell. Uma higher-order function permite abstrair de uma operação específica e passar comportamento como valor.
A diferença chave entre uma higher-order function e uma função comum é a presença de um parâmetro com tipo funcional ou um valor funcional de retorno. Em Kotlin, um tipo funcional é escrito como (ParamType) -> ReturnType. Por exemplo, o tipo (Int) -> String significa uma função que recebe Int e retorna String. O tipo () -> Unit denota uma função sem parâmetros que não retorna um valor útil. É esse sistema de tipos que torna as higher-order functions type-safe.
O oposto de uma higher-order function é uma first-class function (função de primeira classe). First-class function significa que uma função pode ser usada como qualquer outro valor: atribuída a uma variável, armazenada em uma coleção, passada como argumento. Uma higher-order function é uma função que usa first-class functions para receber ou retornar. Kotlin suporta ambos os conceitos no nível da linguagem sem bibliotecas adicionais.
Em Kotlin, qualquer função que tenha pelo menos um parâmetro declarado com um tipo funcional ou cujo tipo de retorno seja funcional é automaticamente considerada uma higher-order function. O compilador não requer uma anotação especial — basta especificar (T) -> R na assinatura. Ao chamar essa função, o argumento é uma expressão lambda, uma referência a uma função existente via ::, ou um valor funcional armazenado em uma variável.
fun operate(a: Int, b: Int, op: (Int, Int) -> Int): Int {
return op(a, b)
}
fun main() {
val sum = operate(10, 20) { x, y -> x + y }
println(sum) // 30
}
No código, a função operate recebe dois inteiros e um parâmetro op do tipo (Int, Int) -> Int. O corpo da função chama a operação passada em uma única linha. Em main, a chamada a operate passa a lambda { x, y -> x + y } — Kotlin a coloca após os parênteses graças à sintaxe de trailing lambda. Se a lambda fosse o último argumento, ela poderia ser movida completamente para fora dos parênteses, o que melhora a legibilidade de cadeias de chamadas.
Internamente, Kotlin compila as higher-order functions através da interface Function (Function2 para dois parâmetros). Cada lambda se transforma em uma classe anônima que implementa a interface FunctionN correspondente. Isso significa que criar uma lambda implica a alocação de um objeto para cada operação. Para reduzir a sobrecarga, Kotlin suporta funções inline, que substituem o corpo da higher-order function no local da chamada, eliminando a criação da classe anônima.
Passar uma função como argumento é o padrão mais comum de uso de higher-order functions. Em vez de criar uma hierarquia de classes com um método polimórfico, o desenvolvedor passa o comportamento desejado diretamente ao ponto de uso. Isso implementa o Princípio Aberto/Fechado sem herança: uma nova operação é adicionada como uma nova lambda, não como uma nova subclasse.
Para funções anuláveis, Kotlin usa o tipo ((T) -> R)? com um ponto de interrogação após os parênteses. Essa função só pode ser chamada após uma verificação de null ou através do operador ?.invoke(). Nesse caso, a assinatura da higher-order function indica explicitamente que passar uma função é opcional — o código chamador pode omitir o argumento. Isso é útil para callbacks e manipuladores de eventos com comportamento opcional.
fun <T> List<T>.customFilter(
predicate: (T) -> Boolean
): List<T> {
val result = mutableListOf<T>()
for (item in this) {
if (predicate(item)) result.add(item)
}
return result
}
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
val even = numbers.customFilter { it % 2 == 0 }
println(even) // [2, 4]
}
A função de extensão customFilter recebe um parâmetro predicate do tipo funcional (T) -> Boolean. Dentro do loop, ela chama predicate para cada elemento e coleta os correspondentes. A chamada em main passa a lambda { it % 2 == 0 }, onde it é o nome implícito do único parâmetro da lambda. Graças às higher-order functions, a lógica de filtragem está completamente isolada do mecanismo de percurso da coleção.
Uma higher-order function pode retornar uma função — esse padrão é chamado de fábrica de funções ou gerador de comportamento. A função retornada pode capturar (closure) variáveis do escopo externo, preservando-as entre chamadas. Isso permite criar manipuladores configuráveis e operações especializadas com base em modelos comuns.
Ao retornar uma função, Kotlin infere o tipo funcional ((T) -> R)? de retorno a partir da assinatura. O compilador verifica que todas as expressões return no corpo retornam valores funcionais compatíveis. As variáveis capturadas são armazenadas no objeto lambda e permanecem acessíveis enquanto existir uma referência a ele. Este é um mecanismo poderoso, mas requer atenção ao gerenciamento de memória.
fun makeMultiplier(factor: Int): (Int) -> Int {
return { x -> x * factor }
}
fun main() {
val double = makeMultiplier(2)
val triple = makeMultiplier(3)
println(double(5)) // 10
println(triple(5)) // 15
}
A função makeMultiplier recebe um factor e retorna uma lambda { x -> x * factor }, onde factor é capturado do escopo externo (closure). Cada chamada a makeMultiplier cria uma nova função com seu próprio valor de factor. As variáveis double e triple armazenam as funções retornadas e podem ser chamadas várias vezes. Esse padrão é amplamente usado na configuração de clientes HTTP, decoradores e middleware.
A combinação de higher-order functions e lambdas permite construir cadeias de operações expressivas sem variáveis intermediárias. A biblioteca padrão do Kotlin contém dezenas de higher-order functions: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy e outras. Cada uma recebe uma lambda e realiza uma transformação de dados com ela.
data class User(val name: String, val age: Int)
fun main() {
val users = listOf(
User("Alice", 25),
User("Bob", 17),
User("Charlie", 30)
)
val result = users
.filter { it.age >= 18 }
.map { it.name.uppercase() }
.sorted()
println(result) // [ALICE, CHARLIE]
}
No exemplo, uma cadeia de três higher-order functions processa uma lista de usuários. filter recebe um predicado, mantendo apenas os adultos. map transforma cada usuário em um nome em maiúsculas. sorted ordena o resultado de forma ascendente. Cada operação recebe uma lambda, e Kotlin garante a segurança de tipos em cada estágio. Sem higher-order functions, seria necessário escrever um loop com if, listas temporárias e ordenação manual.
Perguntas frequentes
Higher-order function recebe outra função como parâmetro ou retorna uma. Uma função comum trabalha apenas com dados — números, strings, objetos. Uma higher-order function trabalha com comportamento, passando a lógica como argumento.
Sim, o modificador inline elimina a sobrecarga de criar uma classe anônima para uma lambda. Usando crossinline ou noinline, você pode controlar quais lambdas são substituídas e quais permanecem como objetos.
Uma função sem parâmetros e sem valor de retorno tem o tipo () -> Unit. Uma função com um parâmetro de tipo T e retorno R é escrita como (T) -> R. Para dois parâmetros — (T, U) -> R, e assim até 22 argumentos.
Uma lambda é uma notação concisa { args -> body }, uma função anônima é fun(args): ReturnType { body }. Uma lambda não pode ter return sem rótulo, uma função anônima pode. Ambas podem ser passadas para uma higher-order function.
Evite higher-order functions em loops críticos sem inline — cada lambda cria um objeto. Para código crítico de desempenho, use inline fun. Também não abuse de lambdas profundamente aninhadas — isso reduz a legibilidade.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também