Inline-functie in Kotlin: wat is het, syntax en toepassing

Auteur: IT Sectr Gepubliceerd: 2026-06-21 Leestijd: 9 min

inline-functie — een Kotlin-mechanisme waarbij het functielichaam tijdens compilatie direct op elke aanroeplocatie wordt ingevoegd. Dit elimineert de overhead van het maken van anonieme klassen en objecten voor lambdaparameters. Volgens Kotlin Documentation, 2025 is het sleutelwoord inline bijzonder effectief voor hogere-ordefuncties, waar elke lambda zonder inlining een apart FunctionN-object creëert en de garbage collector belast.

Belangrijkste punten

  • inline-functie — functie waarvan het lichaam tijdens compilatie op de aanroepplaats wordt ingevoegd
  • Vermindering van overhead — elimineert het maken van anonieme klassen en objecten voor lambda's
  • nonlocal return — lambda's binnen inline-functies kunnen return uitvoeren vanuit de buitenste functie
  • noinline — verbiedt inlining van individuele lambdaparameters
  • crossinline — staat nonlocal return toe, maar verbiedt return vanuit de context van de inline-functie

Wat is een inline-functie in Kotlin?

Een inline-functie is een functie gemarkeerd met het sleutelwoord inline. De Kotlin-compiler maakt er geen aparte bytecode met aanroep voor, maar kopieert het functielichaam direct naar elke aanroeplocatie. Het hoofddoel is optimalisatie van hogere-ordefuncties die lambda-expressies accepteren, omdat elke lambda in normale situaties een anoniem object van de klasse Function creëert.

Volgens JetBrains Tech Blog (2024) kan het gebruik van inline-functies in Kotlin het aantal gemaakte objecten met 40–60% verminderen in functies die intensief lambda's gebruiken. In loops en zwaarbelaste operaties (sorteren, filteren van collecties) geeft dit een meetbare prestatieverbetering.

Zonder inline wordt elke lambda gecompileerd naar een anonieme klasse (of een instantie van een gesynthetiseerde functionele interface). Voor lambda's die variabelen vastleggen, worden extra wrapper-objecten gemaakt. Inline-functies elimineren al deze objecten tijdens compilatie en vervangen ze door directe code met toegang tot lokale variabelen zonder wrappers.

Gebruik inline alleen voor functies met lambdaparameters — de Kotlin-compiler waarschuwt zelf als inline geen voordeel biedt.

Syntax van inline-functie en werkingsmechanisme

Voeg eenvoudig het sleutelwoord inline toe vóór de functiedeclaratie. De compiler voegt automatisch het functielichaam in op de aanroepplaatsen. De functie zelf blijft bestaan in bytecode voor gevallen waarin deze niet direct wordt aangeroepen (bijvoorbeeld vanuit Java-code).

kotlin
inline fun Int.repeatAction(action: (Int) -> Unit) {
    for (i in 0 until this) {
        action(i)
    }
}

// Aanroep — lambdacode wordt ingevoegd in het functielichaam
5.repeatAction { index ->
    println("Index: $index")
}

Na compilatie is bovenstaande code equivalent aan:

kotlin
// Wat gebeurt er na inlining (schematisch):
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

Er wordt geen object voor de lambda gemaakt — de action-code wordt direct uitgevoerd. Dit is de essentie van optimalisatie: in plaats van een Function.invoke()-aanroep — directe invoeging van code met het lambdalichaam.

Controle via decompilatie

Om inlining te controleren, opent u Tools > Kotlin > Show Kotlin Bytecode in IntelliJ IDEA en klikt u op Decompile. U zult zien dat in plaats van de repeatAction-aanroep met lambda, directe invoeging van het functielichaam met een for-lus wordt gegenereerd.

Probleem van lambda-overhead en de oplossing

Elke lambda in Kotlin wordt gecompileerd naar een van drie varianten. Eerste — als de lambda geen variabelen vastlegt, wordt het een statische methode van de klasse waarin deze is gedeclareerd. Tweede — als deze één variabele vastlegt, wordt een anonieme klasse gemaakt. Derde — als deze meerdere variabelen vastlegt, wordt een anonieme klasse gemaakt met velden voor elke vastgelegde variabele.

Type lambdaZonder inlineMet inline
Zonder vastleggingEén statische methode (hergebruikt)Volledige inlining, zonder aanroep
Met vastlegging van 1 variabeleAnonieme klasse (één object)Volledige inlining, zonder object
Met vastlegging van N variabelenAnonieme klasse met N veldenVolledige inlining, zonder object
RecursiefNormale aanroepinline verboden

Volgens Android Performance Patterns (Google, 2024) verminderen inline-functies in apps met intensief gebruik van collecties (filteren, sorteren, groeperen) het aantal allocaties met 25–35%. Het effect is vooral merkbaar in Jetpack Compose, waar elke statusverandering herbewerking met meerdere lambda's veroorzaakt.

Nonlocal return en beperkingen

Een lambda in een gewone functie kan geen return uitvoeren vanuit de buitenste functie — alleen een lokale return vanuit de lambda zelf (via return@label). In een inline-functie wordt de lambda ingevoegd in het lichaam van de aanroepende functie, dus nonlocal return wordt mogelijk: return binnen de lambda beëindigt de buitenste functie.

kotlin
inline fun findFirst(
    items: List<Int>,
    predicate: (Int) -> Boolean
): Int {
    for (item in items) {
        if (predicate(item)) {
            return item
        }
    }
    return -1
}

fun processNumbers() {
    val numbers = listOf(1, 2, 3)
    val firstEven = findFirst(numbers) { it % 2 == 0 }
    // return in lambda zou null retourneren van processNumbers()
}

Nonlocal return is handig voor vroegtijdige beëindiging, maar kan tot fouten leiden. Als de lambda in een niet-lokale context wordt gebruikt (opgeslagen in een variabele), veroorzaakt nonlocal return een RuntimeException. De Kotlin-compiler geeft een waarschuwing bij een poging tot dergelijke opslag.

noinline en crossinline: beheer van inlining

Wanneer een functie meerdere lambdaparameters heeft, moet soms slechts een deel worden ingevoegd. Hiervoor wordt noinline gebruikt — het verbiedt inlining van een specifieke lambdaparameter, waardoor deze als een gewoon Function-object blijft.

De modifier crossinline lost het tegenovergestelde probleem op: de lambda wordt ingevoegd, maar nonlocal return is verboden. Dit is nodig wanneer de lambda binnen een andere lambda wordt gebruikt of in een context waar return niet is toegestaan (bijvoorbeeld doorgegeven aan Runnable).

kotlin
inline fun processWithCallback(
    data: String,
    crossinline onSuccess: (String) -> Unit,
    noinline onError: (Exception) -> Unit
) {
    try {
        val result = process(data)
        onSuccess(result)
    } catch (e: Exception) {
        onError(e)
    }
}

// noinline: onError kan worden opgeslagen in een variabele of elders worden doorgegeven
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

In het voorbeeld is onSuccess gemarkeerd als crossinline — het wordt ingevoegd, maar er kan geen return binnen worden gebruikt. onError is gemarkeerd als noinline — het wordt niet ingevoegd, kan als object worden doorgegeven, in een klassveld worden opgeslagen of als listener worden gebruikt.

Beperkingen van inline-functies en aanbevelingen

Inline-functies hebben beperkingen. Recursieve inline-functies zijn verboden — de compiler geeft een foutmelding. Inline-functies kunnen geen private of internal zichtbaarheid hebben als ze in een andere module zijn gedeclareerd, maar deze beperking heeft te maken met toegang, niet met het inliningsmechanisme zelf.

De bytecodegrootte neemt toe met elke aanroep van een inline-functie, omdat het lichaam wordt gekopieerd. Volgens Kotlin Coding Conventions (JetBrains, 2025) wordt aanbevolen inline alleen te gebruiken voor functies tot 10–15 regels. Voor grote functies kan het voordeel van lambda-inlining worden tenietgedaan door de toename van de APK-grootte (in Android is dit kritiek — er is een limiet van 64K methoden).

kotlin
// Aanbevolen praktijk
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// Niet aanbevolen voor grote functies
inline fun largeComputation(...) { // slecht — lichaam >50 regels
    // meer dan 50 regels — beter om naar een gewone functie te extraheren
}

Publieke inline-functies in bibliotheken vereisen voorzichtigheid: als het lichaam van een inline-functie verandert, moeten alle clients opnieuw compileren. JetBrains raadt het gebruik van @PublishedApi internal aan voor leden die vanuit inline-functies worden aangeroepen, om compatibiliteit binnen de module te behouden.

Veelgestelde vragen

Kan ik een inline-extensiefunctie maken?

Ja, een inline-extensiefunctie werkt zonder beperkingen. Bijvoorbeeld: inline fun String.transform(block: (Char) -> Char): String. De extensie heeft geen invloed op de inliningsmogelijkheid — de compiler behandelt het als een gewone inline-functie.

Wanneer biedt inline GEEN voordeel?

Als de functie geen lambdaparameters accepteert — biedt inline geen voordeel. De Kotlin-compiler geeft een waarschuwing: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Ook is inline schadelijk voor grote functies vanwege de toename van bytecode.

Wat is het verschil tussen inline en @JvmInline (value class)?

inline — een functiemodifier die het functielichaam invoegt op de aanroepplaats. @JvmInline (value class) — een mechanisme voor wrapperklassen die tijdens compilatie worden vervangen door de waarde. Verschillende concepten: inline optimaliseert aanroepen, value class optimaliseert gegevensrepresentatie.

Kan inline worden gebruikt met suspend-functies?

Nee, suspend-functies kunnen niet inline zijn, omdat ze worden gecompileerd naar een statusmachine met Continuation. Een inline-functie kan echter wel een suspend-lambda als parameter met crossinline accepteren. Dit wordt vaak gebruikt in coroutines: inline fun launch(block: suspend CoroutineScope.() -> Unit).

Heeft inline invloed op debuggen?

Ja, inline-functies maken debuggen moeilijker omdat het functielichaam niet wordt aangeroepen maar ingevoegd op de aanroepplaats. De stacktrace wordt langer, breekpunten werken maar kunnen onverwachte posities tonen. JetBrains raadt aan om te debuggen zonder inline en het alleen in release-builds in te schakelen.

Samenvatting

  • inline-functie — voegt het functielichaam in op de aanroepplaats, elimineert lambda-overhead
  • Nonlocal return — return vanuit lambda beëindigt de buitenste functie (alleen mogelijk in inline)
  • noinline — verbiedt inlining van een specifieke lambdaparameter
  • crossinline — staat inlining toe maar verbiedt nonlocal return
  • Recursieve functies kunnen niet inline zijn — de compiler geeft een foutmelding
  • Bytecodegrootte neemt toe — gebruik inline voor functies tot 10–15 regels
  • Optimaal gebruik — hogere-ordefuncties met lambdaparameters, synchronisatieblokken, scope-functies (let, apply, also, run)

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.

Bespreek het project

Lees ook