inline function — mekanismo ng Kotlin kung saan ang katawan ng function ay direktang inilalagay sa bawat lugar ng tawag sa yugto ng kompilasyon. Tinatanggal nito ang overhead mula sa paglikha ng mga anonymous na klase at object para sa mga lambda parameter. Ayon sa Kotlin Documentation, 2025, ang keyword na inline ay lalong epektibo para sa higher-order function, kung saan bawat lambda nang walang pag-embed ay lumilikha ng hiwalay na FunctionN object, na nagpapabigat sa garbage collector.
Mga Pangunahing Punto
Ang inline function ay isang function na minarkahan ng keyword na inline. Ang Kotlin compiler ay hindi lumilikha ng hiwalay na bytecode na may tawag para dito, kundi kinokopya ang katawan ng function nang direkta sa bawat lugar ng tawag. Ang pangunahing layunin — optimisasyon ng higher-order function na tumatanggap ng lambda expression, dahil ang bawat lambda sa normal na sitwasyon ay lumilikha ng anonymous object ng Function class.
Ayon sa JetBrains Tech Blog (2024), ang paggamit ng inline function sa Kotlin ay maaaring mabawasan ang bilang ng mga nilikha na object ng 40–60% sa mga function na intensibong gumagamit ng lambda. Sa mga loop at mataas na kargang operasyon (pag-uuri, pag-filter ng mga koleksyon) ito ay nagbibigay ng nasusukat na pagtaas ng pagganap.
Kung walang inline, ang bawat lambda ay nako-compile sa isang anonymous na klase (o instance ng isang synthesize na functional interface). Para sa mga lambda na kumukuha ng variable, nililikha ang mga karagdagang wrapper object. Tinatanggal ng inline function ang lahat ng mga object na ito sa yugto ng kompilasyon, pinapalitan ang mga ito ng direktang code na may access sa lokal na variable na walang wrapper.
Gamitin ang inline lamang para sa mga function na may lambda parameter — ang Kotlin compiler mismo ay nagbababala kung ang inline ay hindi nagbibigay ng pakinabang.
Sapat na idagdag ang keyword na inline bago ang deklarasyon ng function. Awtomatikong inilalagay ng compiler ang katawan ng function sa mga lugar ng tawag. Ang function mismo ay patuloy na umiiral sa bytecode para sa mga pagkakataon kung saan hindi ito direktang tinatawag (halimbawa, mula sa Java code).
inline fun Int.repeatAction(action: (Int) -> Unit) {
for (i in 0 until this) {
action(i)
}
}
// Tawag — lambda code ay naka-embed sa katawan ng function
5.repeatAction { index ->
println("Index: $index")
}
Pagkatapos ng kompilasyon, ang code sa itaas ay magiging katumbas ng:
// Ano ang mangyayari pagkatapos ng pag-embed (eskematiko):
val $this = 5
for (i in 0 until $this) {
println("Index: $i")
}
Walang object na nilikha para sa lambda — ang action code ay direktang naisasagawa. Ito ang esensya ng optimisasyon: sa halip na tawag ng Function.invoke() — direktang pag-embed ng code na may katawan ng lambda.
Upang suriin ang pag-embed, buksan ang Tools > Kotlin > Show Kotlin Bytecode sa IntelliJ IDEA at pindutin ang Decompile. Makikita mo na sa halip na tawag ng repeatAction na may lambda, direktang pag-embed ng katawan ng function na may for loop ang nabubuo.
Ang bawat lambda sa Kotlin ay nako-compile sa isa sa tatlong variant. Una — kung ang lambda ay hindi kumukuha ng variable, ito ay nagiging static method ng klase kung saan ito na-deklara. Ikalawa — kung kumukuha ng isang variable, nililikha ang anonymous na klase. Ikatlo — kung kumukuha ng maraming variable, nililikha ang anonymous na klase na may mga field para sa bawat nakuhang variable.
| Uri ng Lambda | Walang inline | May inline |
|---|---|---|
| Walang pagkuha | Isang static method (ginagamit muli) | Buong pag-embed, walang tawag |
| May pagkuha ng 1 variable | Anonymous na klase (isang object) | Buong pag-embed, walang object |
| May pagkuha ng N variable | Anonymous na klase na may N field | Buong pag-embed, walang object |
| Rekursibo | Karaniwang tawag | inline bawal |
Ayon sa Android Performance Patterns (Google, 2024), sa mga application na may intensibong paggamit ng koleksyon (pag-filter, pag-uuri, pagpapangkat) ang inline function ay nagbabawas ng bilang ng mga alokasyon ng 25–35%. Ang epekto ay lalong kapansin-pansin sa Jetpack Compose, kung saan ang bawat pagbabago ng estado ay nagdudulot ng muling komposisyon na may maraming lambda.
Ang lambda sa isang ordinaryong function ay hindi maaaring magsagawa ng return mula sa panlabas na function — tanging lokal na return mula sa lambda mismo (sa pamamagitan ng return@label). Sa inline function, ang lambda ay inilalagay sa katawan ng tumatawag na function, kaya nonlocal return ay nagiging posible: ang return sa loob ng lambda ay nagtatapos sa panlabas na function.
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 sa lambda ay magbabalik ng null mula sa processNumbers()
}
Nonlocal return ay maginhawa para sa maagang pagtatapos, ngunit maaaring humantong sa mga error. Kung ang lambda ay ginamit sa nonlocal na konteksto (ini-save sa variable), ang nonlocal return ay magdudulot ng RuntimeException. Ang Kotlin compiler ay naglalabas ng babala sa pagtatangkang mag-save ng ganito.
Kapag ang isang function ay may maraming lambda parameter, minsan kailangan lamang i-embed ang bahagi ng mga ito. Para dito ginagamit ang noinline — nagbabawal sa pag-embed ng isang partikular na lambda parameter, iniiwan ito bilang isang ordinaryong Function object.
Ang modifikator na crossinline ay lumulutas sa kabaligtaran na problema: ang lambda ay naka-embed, ngunit ang nonlocal return ay bawal. Ito ay kailangan kapag ang lambda ay ginamit sa loob ng isa pang lambda o sa konteksto kung saan ang return ay hindi pinapayagan (halimbawa, ipinasa sa 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: ang onError ay maaaring i-save sa variable o ipasa sa ibang lugar
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)
Sa halimbawa, ang onSuccess ay minarkahan bilang crossinline — i-e-embed, ngunit sa loob nito ay hindi maaaring gumamit ng return. Ang onError ay minarkahan bilang noinline — hindi naka-embed, maaaring ipasa bilang object, i-save sa field ng klase, o gamitin bilang listener.
Ang inline function ay may mga limitasyon. Ang mga rekursibong inline function ay bawal — ang compiler ay maglalabas ng error. Ang inline function ay hindi maaaring magkaroon ng private o internal visibility kung sila ay na-deklara sa ibang module, ngunit ang limitasyong ito ay may kinalaman sa access, hindi sa mekanismo ng pag-embed mismo.
Ang laki ng bytecode ay lumalaki sa bawat tawag ng inline function, dahil ang katawan ay kinokopya. Ayon sa Kotlin Coding Conventions (JetBrains, 2025), inirerekomenda na gamitin ang inline lamang para sa mga function na may sukat na hanggang 10–15 linya. Para sa malalaking function, ang pakinabang mula sa pag-embed ng lambda ay maaaring mawala dahil sa pagtaas ng laki ng APK (sa Android ito ay kritikal — may limit na 64K method).
// Inirerekomendang praktika
inline fun withLock(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
} finally {
lock.unlock()
}
}
// Hindi inirerekomenda para sa malalaking function
inline fun largeComputation(...) { // masama — katawan >50 linya
// higit sa 50 linya — mas mahusay na i-extract sa ordinaryong function
}
Ang pampublikong inline function sa mga library ay nangangailangan ng pag-iingat: kung ang katawan ng inline function ay magbabago, lahat ng client ay dapat mag-recompile. Inirerekomenda ng JetBrains ang paggamit ng @PublishedApi internal para sa mga miyembro na tinatawag mula sa inline function, upang mapanatili ang compatibility sa loob ng module.
Mga Madalas Itanong
Oo, ang inline extension function ay gumagana nang walang limitasyon. Halimbawa: inline fun String.transform(block: (Char) -> Char): String. Ang extension ay hindi nakakaapekto sa kakayahang mag-embed — pinoproseso ito ng compiler tulad ng ordinaryong inline function.
Kung ang function ay hindi tumatanggap ng lambda parameter — ang inline ay hindi nagbibigay ng kalamangan. Ang Kotlin compiler ay naglalabas ng babala: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Gayundin, ang inline ay nakakapinsala para sa malalaking function dahil sa paglaki ng bytecode.
inline — modifikator ng function na nag-e-embed ng katawan nito sa lugar ng tawag. @JvmInline (value class) — mekanismo para sa wrapper class na pinapalitan ng halaga sa panahon ng kompilasyon. Magkaibang konsepto: inline ay nag-o-optimize ng mga tawag, value class ay nag-o-optimize ng representasyon ng datos.
Hindi, ang suspend function ay hindi maaaring inline, dahil sila ay nako-compile sa state machine na may Continuation. Gayunpaman, ang inline function ay maaaring tumanggap ng suspend lambda bilang parameter na may crossinline. Ito ay madalas na ginagamit sa coroutine: inline fun launch(block: suspend CoroutineScope.() -> Unit).
Oo, ang inline function ay nagpapahirap sa pag-debug, dahil ang katawan ng function ay hindi tinatawag, kundi naka-embed sa lugar ng tawag. Ang stacktrace ay nagiging mas mahaba, gumagana ang mga breakpoint ngunit maaaring magpakita ng hindi inaasahang posisyon. Inirerekomenda ng JetBrains ang pag-debug nang walang inline, at i-activate lamang ito sa release build.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din