Inline függvény Kotlinban: mi ez, szintaxis és alkalmazás

Szerző: IT Sectr Megjelenés: 2026-06-21 Olvasási idő: 9 perc

inline függvény — Kotlin mechanizmus, amelynél a függvény törzse közvetlenül a hívás helyére illesztődik be a fordítási fázisban. Ez kiküszöböli a névtelen osztályok és objektumok lambda paraméterekhez történő létrehozásának overhead-jét. A Kotlin Documentation, 2025 szerint az inline kulcsszó különösen hatékony magasabb rendű függvényeknél, ahol minden lambda beillesztés nélkül külön FunctionN objektumot hoz létre, terhelve a garbage collector-t.

Főbb pontok

  • inline függvény — függvény, amelynek törzse a hívás helyére illesztődik be a fordítási fázisban
  • Overhead csökkentése — kiküszöböli a névtelen osztályok és objektumok létrehozását a lambdák számára
  • nonlocal return — az inline függvényeken belüli lambdák return-t hajthatnak végre a külső függvényből
  • noinline — megtiltja egyes lambda paraméterek beillesztését
  • crossinline — engedélyezi a nonlocal return-t, de megtiltja a return-t az inline függvény kontextusából

Mi az inline függvény Kotlinban?

Az inline függvény egy inline kulcsszóval megjelölt függvény. A Kotlin fordító nem hoz létre számára külön bájtkódot hívással, hanem közvetlenül a hívás minden helyére másolja a függvény törzsét. A fő cél — a magasabb rendű függvények optimalizálása, amelyek lambda kifejezéseket fogadnak el, mivel minden lambda normál helyzetben létrehozza a Function osztály egy névtelen objektumát.

A JetBrains Tech Blog (2024) szerint az inline függvények használata Kotlinban 40–60%-kal csökkentheti a létrehozott objektumok számát a lambdákat intenzíven használó függvényekben. Ciklusokban és nagy terhelésű műveletekben (rendezés, gyűjtemények szűrése) ez mérhető teljesítménynövekedést eredményez.

Inline nélkül minden lambda egy névtelen osztályba (vagy egy szintetizált funkcionális interfész példányába) fordul. A változókat lezáró lambdák számára további wrapper objektumok jönnek létre. Az inline függvények ezeket az objektumokat a fordítási fázisban megszüntetik, helyükre közvetlen kódot téve, hozzáféréssel a helyi változókhoz wrapper nélkül.

Csak lambda paraméterekkel rendelkező függvényekhez használja az inline-t — a Kotlin fordító maga figyelmeztet, ha az inline nem nyújt előnyt.

Az inline függvény szintaxisa és működési mechanizmusa

Elég az inline kulcsszót hozzáadni a függvény deklarációja elé. A fordító automatikusan beilleszti a függvény törzsét a hívási helyekre. Maga a függvény továbbra is létezik a bájtkódban azokra az esetekre, amikor nem közvetlenül hívják (pl. Java kódból).

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

// Hívás — a lambda kód beillesztődik a függvény törzsébe
5.repeatAction { index ->
    println("Index: $index")
}

A fordítás után a fenti kód egyenértékű lesz a következővel:

kotlin
// Mi történik a beillesztés után (vázlatosan):
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

Nem jön létre objektum a lambda számára — az action kód közvetlenül végrehajtódik. Ez az optimalizálás lényege: a Function.invoke() hívása helyett — a kód közvetlen beillesztése a lambda törzsével.

Ellenőrzés dekompilálással

A beillesztés ellenőrzéséhez nyissa meg a Tools > Kotlin > Show Kotlin Bytecode menüpontot az IntelliJ IDEA-ban, és kattintson a Decompile gombra. Látni fogja, hogy a lambda-val történő repeatAction hívás helyett a függvény törzsének közvetlen beillesztése for ciklussal generálódik.

A lambda overhead problémája és megoldása

Minden lambda Kotlinban a három változat egyikébe fordul. Első — ha a lambda nem zár le változókat, annak az osztálynak a statikus metódusává válik, amelyben deklarálták. Második — ha egy változót zár le, névtelen osztály jön létre. Harmadik — ha több változót zár le, névtelen osztály jön létre mezőkkel minden lezárt változóhoz.

Lambda típusaInline nélkülInline-nal
Lezárás nélkülEgy statikus metódus (újrahasznosítható)Teljes beillesztés, hívás nélkül
1 változó lezárásávalNévtelen osztály (egy objektum)Teljes beillesztés, objektum nélkül
N változó lezárásávalNévtelen osztály N mezővelTeljes beillesztés, objektum nélkül
RekurzívSzokásos hívásinline tiltott

Az Android Performance Patterns (Google, 2024) szerint a gyűjteményeket intenzíven használó alkalmazásokban (szűrés, rendezés, csoportosítás) az inline függvények 25–35%-kal csökkentik a foglalások számát. A hatás különösen észrevehető a Jetpack Compose-ban, ahol minden állapotváltozás újrakompozíciót okoz számos lambdával.

Nonlocal return és korlátozások

A lambda egy szokásos függvényben nem hajthat végre return-t a külső függvényből — csak lokális return-t magából a lambdából (return@label-en keresztül). Az inline függvényben a lambda a hívó függvény törzsébe illesztődik, ezért nonlocal return válik lehetővé: a lambda belsejében lévő return befejezi a külső függvényt.

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 a lambdában null-t adna vissza a processNumbers()-ből
}

Nonlocal return kényelmes a korai befejezéshez, de hibákhoz vezethet. Ha a lambdát nem lokális kontextusban használják (változóba mentik), a nonlocal return RuntimeException-t okoz. A Kotlin fordító figyelmeztetést ad az ilyen mentési kísérletnél.

noinline és crossinline: a beillesztés kezelése

Amikor egy függvénynek több lambda paramétere van, néha csak egy részüket kell beilleszteni. Erre szolgál a noinline — megtiltja egy adott lambda paraméter beillesztését, meghagyva azt szokásos Function objektumként.

A crossinline módosító az ellenkező problémát oldja meg: a lambda beillesztődik, de a nonlocal return tiltott. Ez akkor szükséges, amikor a lambdát egy másik lambdán belül vagy olyan kontextusban használják, ahol a return nem engedélyezett (pl. Runnable-be továbbítva).

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: az onError tárolható változóban vagy továbbítható máshová
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

A példában az onSuccess crossinline-ként van megjelölve — beillesztésre kerül, de belül nem használható return. Az onError noinline-ként van megjelölve — nem illesztődik be, objektumként továbbítható, osztály mezőben tárolható vagy listenerként használható.

Az inline függvények korlátozásai és ajánlások

Az inline függvényeknek korlátozásaik vannak. Rekurzív inline függvények tiltottak — a fordító hibát jelez. Az inline függvények nem rendelkezhetnek private vagy internal láthatósággal, ha másik modulban deklarálták őket, de ez a korlátozás a hozzáférésre vonatkozik, nem magára a beillesztési mechanizmusra.

A bájtkód mérete minden inline függvényhívással nő, mivel a törzs másolódik. A Kotlin Coding Conventions (JetBrains, 2025) szerint ajánlott az inline-t csak 10–15 soros függvényekhez használni. Nagy függvényeknél a lambdák beillesztéséből származó előnyt semlegesítheti az APK méretének növekedése (Androidban ez kritikus — létezik 64K metódus korlát).

kotlin
// Ajánlott gyakorlat
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// Nem ajánlott nagy függvényekhez
inline fun largeComputation(...) { // rossz — törzs >50 sor
    // több mint 50 sor — jobb kivonni egy szokásos függvénybe
}

A könyvtárakban lévő publikus inline függvények óvatosságot igényelnek: ha az inline függvény törzse megváltozik, minden kliensnek újra kell fordítania. A JetBrains a @PublishedApi internal használatát ajánlja az inline függvényekből hívott tagok számára a modulon belüli kompatibilitás megőrzése érdekében.

Gyakran Ismételt Kérdések

Lehet-e inline kiterjesztő függvényt készíteni?

Igen, az inline kiterjesztő függvény korlátozások nélkül működik. Például: inline fun String.transform(block: (Char) -> Char): String. A kiterjesztés nem befolyásolja a beilleszthetőséget — a fordító ugyanúgy kezeli, mint egy szokásos inline függvényt.

Mikor NEM nyújt előnyt az inline?

Ha a függvény nem fogad el lambda paramétereket — az inline nem nyújt előnyt. A Kotlin fordító figyelmeztetést ad: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Továbbá az inline káros a nagy függvényekre a bájtkód növekedése miatt.

Miben különbözik az inline a @JvmInline-tól (value class)?

inline — függvény módosító, amely a függvény törzsét a hívás helyére illeszti. @JvmInline (value class) — mechanizmus a wrapper osztályok számára, amelyek a fordítás során értékkel helyettesítődnek. Különböző koncepciók: inline a hívásokat optimalizálja, value class az adatábrázolást optimalizálja.

Használható-e az inline suspend függvényekkel?

Nem, a suspend függvények nem lehetnek inline, mivel állapotgéppé fordulnak Continuation-nel. Az inline függvény azonban fogadhat suspend lambdát paraméterként crossinline-nal. Ezt gyakran használják korutinokban: inline fun launch(block: suspend CoroutineScope.() -> Unit).

Befolyásolja-e az inline a hibakeresést?

Igen, az inline függvények megnehezítik a hibakeresést, mivel a függvény törzse nem hívódik, hanem a hívás helyére illesztődik be. A stacktrace hosszabb lesz, a töréspontok működnek, de váratlan pozíciókat mutathatnak. A JetBrains azt ajánlja, hogy inline nélkül végezze a hibakeresést, és csak release build-ekben kapcsolja be.

Összefoglaló

  • inline függvény — a függvény törzsét a hívás helyére illeszti, kiküszöbölve a lambda overhead-et
  • Nonlocal return — a lambdából való return befejezi a külső függvényt (csak inline-ban lehetséges)
  • noinline — megtiltja egy adott lambda paraméter beillesztését
  • crossinline — engedélyezi a beillesztést, de megtiltja a nonlocal return-t
  • Rekurzív függvények nem lehetnek inline — a fordító hibát jelez
  • Bájtkód mérete nő — használja az inline-t 10–15 soros függvényekhez
  • Optimális alkalmazás — magasabb rendű függvények lambda paraméterekkel, szinkronizációs blokkok, scope függvények (let, apply, also, run)

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is