Higher-order function — is een functie die een andere functie als parameter accepteert of een functie als resultaat retourneert. In Kotlin zijn functies eersteklas objecten: ze kunnen worden opgeslagen in variabelen, doorgegeven als argumenten en geretourneerd. Volgens Kotlin-documentatie (2026) verminderen higher-order functions het dupliceren van code gemiddeld met 30% in vergelijking met imperatieve benaderingen. Higher-order function — een fundamenteel concept van de functionele stijl in moderne ontwikkeling.
Belangrijkste punten
Higher-order function — is een functie die ten minste een van twee kenmerken heeft: het accepteren van een andere functie als argument of het retourneren van een functie als resultaat. In de wiskunde worden dergelijke functies functionalen of operatoren genoemd. In de programmering verschenen ze in Lisp in 1958 en werden ze een verplicht onderdeel van alle moderne talen — JavaScript, Python, Swift, Kotlin, Scala en Haskell. Higher-order function maakt het mogelijk om te abstraheren van een specifieke bewerking en gedrag als waarde door te geven.
Het belangrijkste verschil tussen een higher-order function en een gewone functie — de aanwezigheid van een parameter met een functioneel type of een geretourneerde functionele waarde. In Kotlin wordt het functionele type geschreven als (ParamType) -> ReturnType. Bijvoorbeeld, het type (Int) -> String betekent een functie die Int accepteert en String retourneert. Het type () -> Unit geeft een functie zonder parameters aan die geen nuttige waarde retourneert. Juist dit typesysteem maakt higher-order functions typeveilig.
Het tegenovergestelde van een higher-order function — first-class function (eersteklas functie). First-class function betekent dat een functie als elke andere waarde kan worden gebruikt: toegewezen aan een variabele, opgeslagen in een collectie, doorgegeven als argument. Higher-order function is een functie die first-class functions gebruikt om te accepteren of te retourneren. Kotlin ondersteunt beide concepten op taalniveau zonder extra bibliotheken.
In Kotlin wordt elke functie die ten minste één parameter heeft gedeclareerd met een functioneel type of waarvan het retourtype functioneel is, automatisch beschouwd als een higher-order function. De compiler vereist geen speciale annotatie — het is voldoende om (T) -> R in de handtekening te specificeren. Bij het aanroepen van zo'n functie wordt als argument ofwel een lambda-expressie, ofwel een verwijzing naar een bestaande functie via ::, ofwel een functionele waarde opgeslagen in een variabele doorgegeven.
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
}
In de listing accepteert de functie operate twee gehele getallen en de parameter op van het type (Int, Int) -> Int. Het lichaam van de functie roept in één regel de doorgegeven bewerking aan. In main geeft de aanroep operate de lambda { x, y -> x + y } door — Kotlin plaatst deze na de haakjes dankzij de trailing lambda-syntax. Als de lambda het laatste argument was, zou deze volledig buiten de haakjes kunnen worden geplaatst, wat de leesbaarheid van aanroepketens verhoogt.
Onder de motorkap compileert Kotlin de higher-order function via de Function-interface (Function2 voor twee parameters). Elke lambda wordt omgezet in een anonieme klasse die de bijbehorende FunctionN-interface implementeert. Dit betekent dat het maken van een lambda leidt tot toewijzing van een object voor elke bewerking. Om overhead te verminderen, ondersteunt Kotlin inline-functies, die het lichaam van de higher-order function op de aanroepplaats invoegen, waardoor het maken van een anonieme klasse wordt geëlimineerd.
Het doorgeven van een functie als argument — het meest voorkomende patroon voor het gebruik van een higher-order function. In plaats van een hiërarchie van klassen met een polymorfe methode te creëren, geeft de programmeur het gewenste gedrag rechtstreeks op het gebruikspunt door. Dit implementeert het Open/Gesloten Principe (Open/Closed Principle) zonder overerving: een nieuwe bewerking wordt toegevoegd als een nieuwe lambda, niet als een nieuwe subklasse.
Voor nullable-functies gebruikt Kotlin het type ((T) -> R)? met een vraagteken na de haakjes. Zo'n functie kan alleen worden aangeroepen na een null-controle of via de operator ?.invoke(). De handtekening van de higher-order function geeft duidelijk aan dat het doorgeven van de functie niet verplicht is — de aanroepende code kan het argument weglaten. Dit is handig voor callbacks en gebeurtenishandlers met optioneel gedrag.
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]
}
De extensiefunctie customFilter accepteert de parameter predicate van het functionele type (T) -> Boolean. Binnen de lus roept het predicate aan voor elk element en verzamelt de overeenkomende. De aanroep in main geeft de lambda { it % 2 == 0 } door, waarbij it de impliciete naam is van de enige parameter van de lambda. Dankzij de higher-order function is de filterlogica volledig gescheiden van het mechanisme om de collectie te doorlopen.
Een higher-order function kan een functie retourneren — zo'n patroon wordt een functiefabriek of gedragsgenerator genoemd. De geretourneerde functie kan variabelen uit het externe bereik vastleggen (closure) en ze tussen aanroepen behouden. Dit maakt het mogelijk om configureerbare handlers en gespecialiseerde bewerkingen te creëren op basis van algemene sjablonen.
Bij het retourneren van een functie leidt Kotlin het geretourneerde functionele type ((T) -> R)? af uit de handtekening. De compiler controleert dat alle return-expressies in het lichaam compatibele functionele waarden retourneren. Vastgelegde variabelen worden opgeslagen in het lambda-object en zijn toegankelijk zolang er een verwijzing naar bestaat. Dit is een krachtig mechanisme, maar vereist aandacht bij geheugenbeheer.
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
}
De functie makeMultiplier accepteert factor en retourneert de lambda { x -> x * factor }, waarbij factor is vastgelegd uit het externe bereik (closure). Bij elke aanroep van makeMultiplier wordt een nieuwe functie gemaakt met zijn eigen factor-waarde. De variabelen double en triple slaan de geretourneerde functies op en kunnen meerdere keren worden aangeroepen. Dit patroon wordt veel gebruikt bij het configureren van HTTP-cliënten, decorators en middleware.
Gecombineerd gebruik van higher-order function en lambdas maakt het mogelijk om expressieve bewerkingsketens te bouwen zonder tussenliggende variabelen. De standaardbibliotheek van Kotlin bevat tientallen higher-order functions: let, run, apply, also, filter, map, flatMap, fold, reduce, forEach, groupBy en andere. Elk van hen accepteert een lambda en voert daarmee gegevenstransformatie uit.
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]
}
In het voorbeeld verwerkt een keten van drie higher-order functions een lijst met gebruikers. filter accepteert een predicaat en houdt alleen meerderjarige gebruikers over. map transformeert elke gebruiker naar een naam in hoofdletters. sorted sorteert het resultaat oplopend. Elke bewerking accepteert een lambda en Kotlin zorgt voor typeveiligheid in alle fasen. Zonder higher-order function zou een lus met if, tijdelijke lijsten en handmatig sorteren moeten worden geschreven.
Veelgestelde vragen
Higher-order function accepteert een andere functie als parameter of retourneert deze. Een gewone functie werkt alleen met gegevens — getallen, strings, objecten. Een higher-order function werkt met gedrag en geeft logica door als argument.
Ja, de inline-modificator elimineert de overhead van het maken van een anonieme klasse voor de lambda. Met crossinline of noinline kan worden beheerd welke lambdas worden ingevoegd en welke objecten blijven.
Een functie zonder parameters en zonder retourwaarde heeft het type () -> Unit. Een functie met één parameter van type T en retournering R wordt geschreven als (T) -> R. Voor twee parameters — (T, U) -> R en zo verder tot 22 argumenten.
Lambda — compacte notatie { args -> body }, anonieme functie — fun(args): ReturnType { body }. Lambda kan geen return zonder label hebben, anonieme functie wel. Beide kunnen worden doorgegeven aan een higher-order function.
Vermijd higher-order functions in hete lussen zonder inline — elke lambda creëert een object. Gebruik voor kritieke prestaties inline fun. Misbruik ook geen diepe nesting van lambdas — dit vermindert de leesbaarheid.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook