inline-funktion — en Kotlin-mekanism där funktionens kropp sätts in direkt på varje anropsplats vid kompileringstillfället. Detta eliminerar overhead från att skapa anonyma klasser och objekt för lambdaparametrar. Enligt Kotlin Documentation, 2025 är nyckelordet inline särskilt effektivt för högre ordningens funktioner, där varje lambda utan inlinearning skapar ett separat FunctionN-objekt, vilket belastar garbage collectorn.
Huvudpunkter
En inline-funktion är en funktion markerad med nyckelordet inline. Kotlin-kompilatorn skapar inte separat bytekod med anrop för den, utan kopierar funktionens kropp direkt till varje anropsplats. Huvudmålet är optimering av högre ordningens funktioner som accepterar lambdauttryck, eftersom varje lambda i normala fall skapar ett anonymt objekt av klassen Function.
Enligt JetBrains Tech Blog (2024) kan användning av inline-funktioner i Kotlin minska antalet skapade objekt med 40–60% i funktioner som intensivt använder lambdor. I loopar och högt belastade operationer (sortering, filtrering av samlingar) ger detta en mätbar prestandaökning.
Utan inline kompileras varje lambda till en anonym klass (eller en instans av ett syntetiserat funktionellt gränssnitt). För lambdor som fångar variabler skapas ytterligare wrapper-objekt. Inline-funktioner eliminerar alla dessa objekt vid kompilering och ersätter dem med direkt kod med åtkomst till lokala variabler utan wrappers.
Använd inline endast för funktioner med lambdaparametrar — Kotlin-kompilatorn varnar själv om inline inte ger fördel.
Det räcker att lägga till nyckelordet inline före funktionsdeklarationen. Kompilatorn sätter automatiskt in funktionens kropp på anropsplatserna. Själva funktionen fortsätter att finnas i bytekoden för fall där den inte anropas direkt (t.ex. från Java-kod).
inline fun Int.repeatAction(action: (Int) -> Unit) {
for (i in 0 until this) {
action(i)
}
}
// Anrop — lambdakod inlineas i funktionens kropp
5.repeatAction { index ->
println("Index: $index")
}
Efter kompilering kommer ovanstående kod att vara ekvivalent med:
// Vad händer efter inlinearning (schematiskt):
val $this = 5
for (i in 0 until $this) {
println("Index: $i")
}
Inget objekt skapas för lambdan — action-koden körs direkt. Detta är kärnan i optimeringen: istället för ett anrop till Function.invoke() — direkt insättning av kod med lambdans kropp.
För att kontrollera inlinearning, öppna Tools > Kotlin > Show Kotlin Bytecode i IntelliJ IDEA och klicka på Decompile. Du kommer att se att istället för repeatAction-anrop med lambda genereras direkt insättning av funktionens kropp med en for-loop.
Varje lambda i Kotlin kompileras till en av tre varianter. Första — om lambdan inte fångar variabler blir den en statisk metod för klassen där den deklarerades. Andra — om den fångar en variabel skapas en anonym klass. Tredje — om den fångar flera variabler skapas en anonym klass med fält för varje fångad variabel.
| Typ av lambda | Utan inline | Med inline |
|---|---|---|
| Utan fångst | En statisk metod (återanvänds) | Fullständig inlinearning, utan anrop |
| Med fångst av 1 variabel | Anonym klass (ett objekt) | Fullständig inlinearning, utan objekt |
| Med fångst av N variabler | Anonym klass med N fält | Fullständig inlinearning, utan objekt |
| Rekursiv | Vanligt anrop | inline förbjudet |
Enligt Android Performance Patterns (Google, 2024) minskar inline-funktioner antalet allokeringar med 25–35% i applikationer med intensiv användning av samlingar (filtrering, sortering, gruppering). Effekten är särskilt märkbar i Jetpack Compose, där varje tillståndsförändring orsakar omkomposition med flera lambdor.
En lambda i en vanlig funktion kan inte utföra return från den yttre funktionen — endast lokal return från själva lambdan (via return@label). I en inline-funktion sätts lambdan in i den anropande funktionens kropp, därför blir nonlocal return möjlig: return inuti lambdan avslutar den yttre funktionen.
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 i lambdan skulle returnera null från processNumbers()
}
Nonlocal return är praktisk för tidig avslutning, men kan leda till fel. Om lambdan används i en icke-lokal kontext (sparas i en variabel) kommer nonlocal return att orsaka ett RuntimeException. Kotlin-kompilatorn utfärdar en varning vid försök till sådan lagring.
När en funktion har flera lambdaparametrar behöver ibland bara en del av dem inlineas. För detta används noinline — det förbjuder inlinearning av en specifik lambdaparameter och lämnar den som ett vanligt Function-objekt.
Modifieraren crossinline löser det motsatta problemet: lambdan inlineas, men nonlocal return är förbjuden. Detta behövs när lambdan används inuti en annan lambda eller i en kontext där return inte är tillåten (t.ex. skickas till Runnable).
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 lagras i en variabel eller skickas vidare
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)
I exemplet är onSuccess markerad som crossinline — den kommer att inlineas, men inuti den kan return inte användas. onError är markerad som noinline — den inlineas inte, kan skickas som objekt, lagras i ett klassfält eller användas som listener.
Inline-funktioner har begränsningar. Rekursiva inline-funktioner är förbjudna — kompilatorn ger ett fel. Inline-funktioner kan inte ha private eller internal synlighet om de deklareras i en annan modul, men denna begränsning gäller åtkomst, inte själva inlinearingsmekanismen.
Bytekodens storlek ökar med varje anrop av en inline-funktion, eftersom kroppen kopieras. Enligt Kotlin Coding Conventions (JetBrains, 2025) rekommenderas att använda inline endast för funktioner upp till 10–15 rader. För stora funktioner kan fördelen med lambda-inlinearning uppvägas av ökningen av APK-storleken (i Android är detta kritiskt — det finns en gräns på 64K metoder).
// Rekommenderad praxis
inline fun withLock(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
} finally {
lock.unlock()
}
}
// Rekommenderas inte för stora funktioner
inline fun largeComputation(...) { // dåligt — kropp >50 rader
// mer än 50 rader — bättre att extrahera till en vanlig funktion
}
Offentliga inline-funktioner i bibliotek kräver försiktighet: om kroppen av en inline-funktion ändras måste alla klienter kompilera om. JetBrains rekommenderar att använda @PublishedApi internal för medlemmar som anropas från inline-funktioner för att behålla kompatibilitet inom modulen.
Vanliga frågor
Ja, en inline-tilläggsfunktion fungerar utan begränsningar. Till exempel: inline fun String.transform(block: (Char) -> Char): String. Tillägget påverkar inte inlinearingsförmågan — kompilatorn behandlar den som en vanlig inline-funktion.
Om funktionen inte accepterar lambdaparametrar — ger inline ingen fördel. Kotlin-kompilatorn utfärdar en varning: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Dessutom är inline skadlig för stora funktioner på grund av bytekodens tillväxt.
inline — en funktionsmodifierare som sätter in funktionens kropp på anropsplatsen. @JvmInline (value class) — en mekanism för wrapper-klasser som ersätts med värdet under kompilering. Olika koncept: inline optimerar anrop, value class optimerar datarepresentation.
Nej, suspend-funktioner kan inte vara inline eftersom de kompileras till en tillståndsmaskin med Continuation. En inline-funktion kan dock acceptera en suspend-lambda som parameter med crossinline. Detta används ofta i korutiner: inline fun launch(block: suspend CoroutineScope.() -> Unit).
Ja, inline-funktioner försvårar felsökning eftersom funktionens kropp inte anropas utan sätts in på anropsplatsen. Stacktrace blir längre, brytpunkter fungerar men kan visa oväntade positioner. JetBrains rekommenderar felsökning utan inline och att aktivera det endast i release-byggen.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också