Инлине функција у Котлину: шта је то, синтакса и примена

Аутор: IT Sectr Објављено: 2026-06-21 Време читања: 9 мин

инлине функција — механизам у Котлину при којем се тело функције убацује директно на свако место позива у фази компилације. Ово елиминише overhead од стварања анонимних класа и објеката за ламбда параметре. Према Kotlin Documentation, 2025, кључна реч inline је посебно ефикасна за функције вишег реда, где свака ламбда без уграђивања ствара засебан објекат FunctionN, оптерећујући сакупљач отпада.

Главно

  • инлине функција — функција чије се тело убацује на место позива у фази компилације
  • Смањење overhead-а — елиминише стварање анонимних класа и објеката за ламбде
  • nonlocal return — ламбде унутар инлине функција могу да изврше return из спољашње функције
  • noinline — забрањује уграђивање појединих ламбда параметара
  • crossinline — дозвољава nonlocal return, али забрањује return из контекста инлине функције

Шта је инлине функција у Котлину?

Инлине функција је функција означена кључном речи inline. Компилатор Котлина не ствара за њу засебан бајткод са позивом, већ копира тело функције директно на свако место позива. Основни циљ — оптимизација функција вишег реда које прихватају ламбда изразе, јер свака ламбда у нормалној ситуацији ствара анонимни објекат класе Function.

Према JetBrains Tech Blog (2024), употреба инлине функција у Котлину може смањити број створених објеката за 40–60% у функцијама које интензивно користе ламбде. У петљама и високо оптерећеним операцијама (сортирање, филтрирање колекција) ово даје мерљив пораст перформанси.

Без inline-а свака ламбда се компилира у анонимну класу (или инстанцу синтетизованог функционалног интерфејса). За ламбде које хватају променљиве стварају се додатни објекти-омотачи. Инлине функције елиминишу све ове објекте у фази компилације, замењујући их директним кодом са приступом локалним променљивим без омотача.

Користите inline само за функције са ламбда параметрима — компилатор Котлина сам упозорава ако inline не доноси корист.

Синтакса инлине функције и механизам рада

Довољно је додати кључну реч inline пре декларације функције. Компилатор аутоматски убацује тело функције на места позива. Сама функција наставља да постоји у бајткоду за случајеве када се не позива директно (нпр. из Java кода).

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

// Позив — ламбда код се уграђује у тело функције
5.repeatAction { index ->
    println("Index: $index")
}

Након компилације, горњи код ће бити еквивалентан:

kotlin
// Шта се дешава након уграђивања (шематски):
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

Не ствара се ниједан објекат за ламбду — код action се извршава директно. Ово је суштина оптимизације: уместо позива Function.invoke() — директно убацивање кода са телом ламбде.

Провера путем декомпилације

Да бисте проверили уграђивање, отворите Tools > Kotlin > Show Kotlin Bytecode у IntelliJ IDEA и кликните Decompile. Видећете да се уместо позива repeatAction са ламбдом генерише директно убацивање тела функције са for петљом.

Проблем overhead-а ламбди и његово решење

Свака ламбда у Котлину се компилира у једну од три варијанте. Прва — ако ламбда не хвата променљиве, постаје статички метод класе у којој је декларисана. Друга — ако хвата једну променљиву, ствара се анонимна класа. Трећа — ако хвата више променљивих, ствара се анонимна класа са пољима за сваку захваћену променљиву.

Тип ламбдеБез inlineСа inline
Без хватањаЈедан статички метод (поново се користи)Потпуно уграђивање, без позива
Са хватањем 1 променљивеАнонимна класа (један објекат)Потпуно уграђивање, без објекта
Са хватањем N променљивихАнонимна класа са N пољаПотпуно уграђивање, без објекта
РекурзивнаОбичан позивinline забрањен

Према Android Performance Patterns (Google, 2024), у апликацијама са интензивном употребом колекција (филтрирање, сортирање, груписање) инлине функције смањују број алокација за 25–35%. Ефекат је посебно приметан у Jetpack Compose, где свака промена стања изазива поновну композицију са мноштвом ламбди.

Nonlocal return и ограничења

Ламбда у обичној функцији не може да изврши return из спољашње функције — само локални return из саме ламбде (преко return@label). У инлине функцији, ламбда се убацује у тело функције која позива, зато nonlocal return постаје могућ: return унутар ламбде завршава спољашњу функцију.

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 у ламбди би вратио null из processNumbers()
}

Nonlocal return је згодан за превремени завршетак, али може довести до грешака. Ако се ламбда користи у нелокалном контексту (чува се у променљивој), nonlocal return ће изазвати RuntimeException. Компилатор Котлина издаје упозорење при покушају таквог чувања.

noinline и crossinline: управљање уграђивањем

Када функција има више ламбда параметара, понекад је потребно уградити само део њих. За то се користи noinline — забрањује уграђивање одређеног ламбда параметра, остављајући га као обичан објекат Function.

Модификатор crossinline решава супротан задатак: ламбда се уграђује, али nonlocal return се забрањује. Ово је потребно када се ламбда користи унутар друге ламбде или у контексту где return није дозвољен (нпр. прослеђује се у 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 може бити ускладиштен у променљивој или прослеђен другде
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

У примеру onSuccess је означена као crossinline — биће уграђена, али унутар ње не може да се користи return. onError је означена као noinline — не уграђује се, може се прослеђивати као објекат, чувати у пољу класе или користити као listener.

Ограничења инлине функција и препоруке

Инлине функције имају ограничења. Рекурзивне инлине функције су забрањене — компилатор ће пријавити грешку. Инлине функције не могу имати видљивост private или internal ако су декларисане у другом модулу, али ово ограничење је везано за приступ, а не за сам механизам уграђивања.

Величина бајткода расте са сваким позивом инлине функције, јер се тело копира. Према Kotlin Coding Conventions (JetBrains, 2025), препоручује се коришћење inline само за функције величине до 10–15 линија. За велике функције, добит од уграђивања ламбди може бити поништена повећањем величине APK-а (у Android-у је ово критично — постоји лимит од 64K метода).

kotlin
// Препоручена пракса
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// Није препоручено за велике функције
inline fun largeComputation(...) { // лоше — тело >50 линија
    // више од 50 линија — боље издвојити у обичну функцију
}

Јавне инлине функције у библиотекама захтевају опрез: ако се тело инлине функције промени, сви клијенти морају поново да компилирају. JetBrains препоручује коришћење @PublishedApi internal за чланове који се позивају из инлине функција, како би се очувала компатибилност у оквиру модула.

Често постављана питања

Може ли се направити inline extension функција?

Да, inline extension функција ради без ограничења. На пример: inline fun String.transform(block: (Char) -> Char): String. Проширење не утиче на могућност уграђивања — компилатор је обрађује исто као обичну инлине функцију.

Када inline НЕ доноси корист?

Ако функција не прихвата ламбда параметре — inline не даје предност. Компилатор Котлина издаје упозорење: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Такође, inline је штетан за велике функције због раста бајткода.

По чему се inline разликује од @JvmInline (value class)?

inline — модификатор функције који уграђује њено тело на место позива. @JvmInline (value class) — механизам за класе-омотаче које се замењују вредношћу током компилације. Различити концепти: inline оптимизује позиве, value class оптимизује представљање података.

Може ли се користити inline са suspend функцијама?

Не, suspend функције не могу бити inline, јер се компилирају у state машину са Continuation. Међутим, инлине функција може прихватити suspend ламбду као параметар са crossinline. Ово се често користи у корутинама: inline fun launch(block: suspend CoroutineScope.() -> Unit).

Да ли inline утиче на отклањање грешака?

Да, инлине функције отежавају отклањање грешака, јер се тело функције не позива, већ уграђује на место позива. Stacktrace постаје дужи, тачке прекида раде, али могу приказивати неочекиване позиције. JetBrains препоручује отклањање грешака без inline-а, а укључивање само у release верзијама.

Закључак

  • инлине функција — уграђује тело функције на место позива, елиминишући overhead ламбди
  • Nonlocal return — return из ламбде завршава спољашњу функцију (могуће само у inline)
  • noinline — забрањује уграђивање одређеног ламбда параметра
  • crossinline — дозвољава уграђивање, али забрањује nonlocal return
  • Рекурзивне функције не могу бити inline — компилатор пријављује грешку
  • Величина бајткода расте — користите inline за функције до 10–15 линија
  • Оптимална примена — функције вишег реда са ламбда параметрима, блокови синхронизације, scope functions (let, apply, also, run)

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође