inline funksiya — Kotlin mexanizmi, bu zaman funksiyanın gövdəsi kompilasiya mərhələsində birbaşa hər çağrı yerinə yerləşdirilir. Bu, lambda parametrləri üçün anonim siniflərin və obyektlərin yaradılması overhead-ini aradan qaldırır. Kotlin Documentation, 2025-ə görə, inline açar sözü xüsusilə yüksək səviyyəli funksiyalar üçün effektivdir, burada hər lambda yerləşdirmə olmadan ayrıca FunctionN obyekti yaradır və garbage collector-u yükləyir.
Əsas məqamlar
Inline funksiya — inline açar sözü ilə işarələnmiş funksiyadır. Kotlin kompilatoru onun üçün çağrı ilə ayrıca bayt-kod yaratmır, əksinə funksiyanın gövdəsini birbaşa hər çağrı yerinə kopyalayır. Əsas məqsəd — lambda ifadələrini qəbul edən yüksək səviyyəli funksiyaların optimallaşdırılmasıdır, çünki hər lambda normal vəziyyətdə Function sinfinin anonim obyektini yaradır.
JetBrains Tech Blog (2024)-ə görə, Kotlin-də inline funksiyaların istifadəsi lambdalardan intensiv istifadə edən funksiyalarda yaradılan obyektlərin sayını 40–60% azalda bilər. Dövrlərdə və yüksək yüklü əməliyyatlarda (çeşidləmə, kolleksiyaların filtrasiyası) bu, ölçülə bilən performans artımı verir.
Inline olmadan hər lambda anonim sinifə (və ya sintez edilmiş funksional interfeysin instansına) kompilasiya olunur. Dəyişənləri tutan lambdalar üçün əlavə sarğı obyektləri yaradılır. Inline funksiyalar bütün bu obyektləri kompilasiya mərhələsində aradan qaldırır, onları sarğısız lokal dəyişənlərə girişi olan birbaşa kodla əvəz edir.
Inline-dən yalnız lambda parametrləri olan funksiyalar üçün istifadə edin — Kotlin kompilatoru inline fayda vermədikdə özü xəbərdarlıq edir.
Funksiya bəyannaməsindən əvvəl inline açar sözünü əlavə etmək kifayətdir. Kompilator avtomatik olaraq funksiyanın gövdəsini çağrı yerlərinə yerləşdirir. Funksiyanın özü bayt-kodda birbaşa çağrılmadığı hallar üçün (məsələn, Java kodundan) mövcud olaraq qalır.
inline fun Int.repeatAction(action: (Int) -> Unit) {
for (i in 0 until this) {
action(i)
}
}
// Çağrı — lambda kodu funksiyanın gövdəsinə yerləşdirilir
5.repeatAction { index ->
println("Index: $index")
}
Kompilasiyadan sonra yuxarıdakı kod aşağıdakına ekvivalent olacaq:
// Yerləşdirmədən sonra nə baş verir (sxematik):
val $this = 5
for (i in 0 until $this) {
println("Index: $i")
}
Lambda üçün heç bir obyekt yaradılmır — action kodu birbaşa icra olunur. Optimallaşdırmanın mahiyyəti budur: Function.invoke() çağrısı əvəzinə — lambda gövdəsi ilə kodun birbaşa yerləşdirilməsi.
Yerləşdirməni yoxlamaq üçün IntelliJ IDEA-da Tools > Kotlin > Show Kotlin Bytecode açın və Decompile düyməsini basın. Görəcəksiniz ki, lambda ilə repeatAction çağrısı əvəzinə for dövrü ilə funksiya gövdəsinin birbaşa yerləşdirilməsi generasiya olunur.
Kotlin-də hər lambda üç variantdan birinə kompilasiya olunur. Birinci — lambda dəyişənləri tutmursa, o, bəyan olunduğu sinfin statik metoduna çevrilir. İkinci — bir dəyişəni tutursa, anonim sinif yaradılır. Üçüncü — bir neçə dəyişəni tutursa, hər tutulan dəyişən üçün sahələri olan anonim sinif yaradılır.
| Lambda növü | Inline olmadan | Inline ilə |
|---|---|---|
| Tutma yoxdur | Bir statik metod (təkrar istifadə olunur) | Tam yerləşdirmə, çağrısız |
| 1 dəyişənin tutulması | Anonim sinif (bir obyekt) | Tam yerləşdirmə, obyektsiz |
| N dəyişənin tutulması | N sahəli anonim sinif | Tam yerləşdirmə, obyektsiz |
| Rekursiv | Adi çağrı | inline qadağandır |
Android Performance Patterns (Google, 2024)-ə görə, kolleksiyalardan intensiv istifadə edən tətbiqlərdə (filtrasiya, çeşidləmə, qruplaşdırma) inline funksiyalar alokasiyaların sayını 25–35% azaldır. Effekt xüsusilə Jetpack Compose-da nəzərə çarpır, burada hər vəziyyət dəyişikliyi çoxsaylı lambdalarla yenidən kompozisiyaya səbəb olur.
Adi funksiyadakı lambda xarici funksiyadan return edə bilməz — yalnız lambdanın özündən lokal return (return@label vasitəsilə). Inline funksiyada lambda çağıran funksiyanın gövdəsinə yerləşdirilir, buna görə də nonlocal return mümkün olur: lambda daxilindəki return xarici funksiyanı bitirir.
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 }
// lambdadakı return processNumbers() funksiyasından null qaytarardı
}
Nonlocal return vaxtından əvvəl bitirmək üçün rahatdır, lakin səhvlərə səbəb ola bilər. Lambda qeyri-lokal kontekstdə istifadə olunarsa (dəyişənə saxlanılarsa), nonlocal return RuntimeException-a səbəb olacaq. Kotlin kompilatoru belə saxlama cəhdində xəbərdarlıq edir.
Funksiyanın bir neçə lambda parametri olduqda, bəzən yalnız bir hissəsini yerləşdirmək lazım gəlir. Bunun üçün noinline istifadə olunur — müəyyən lambda parametrinin yerləşdirilməsini qadağan edir, onu adi Function obyekti kimi saxlayır.
crossinline modifikatoru əks məsələni həll edir: lambda yerləşdirilir, lakin nonlocal return qadağan edilir. Bu, lambda başqa lambda daxilində və ya return-ün icazə verilmədiyi kontekstdə istifadə edildikdə lazımdır (məsələn, Runnable-ə ötürülərkən).
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 dəyişəndə saxlanıla və ya başqa yerə ötürülə bilər
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)
Nümunədə onSuccess crossinline olaraq işarələnib — yerləşdiriləcək, lakin onun daxilində return istifadə etmək olmaz. onError noinline olaraq işarələnib — yerləşdirilmir, onu obyekt kimi ötürmək, sinif sahəsində saxlamaq və ya listener kimi istifadə etmək olar.
Inline funksiyaların məhdudiyyətləri var. Rekursiv inline funksiyalar qadağandır — kompilator xəta verəcək. Inline funksiyalar başqa modulda bəyan olunubsa, private və ya internal görünürlüyünə malik ola bilməz, lakin bu məhdudiyyət girişlə bağlıdır, yerləşdirmə mexanizmi ilə deyil.
Bayt-kodun ölçüsü hər inline funksiya çağrısı ilə artır, çünki gövdə kopyalanır. Kotlin Coding Conventions (JetBrains, 2025)-ə görə, inline-dən yalnız 10–15 sətirə qədər olan funksiyalar üçün istifadə etmək tövsiyə olunur. Böyük funksiyalar üçün lambdaların yerləşdirilməsindən əldə olunan qazanc APK ölçüsünün artması ilə itirilə bilər (Android-də bu kritikdir — 64K metod limiti var).
// Tövsiyə olunan təcrübə
inline fun withLock(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
} finally {
lock.unlock()
}
}
// Böyük funksiyalar üçün tövsiyə edilmir
inline fun largeComputation(...) { // pis — gövdə >50 sətir
// 50 sətirdən çox — adi funksiyaya ayırmaq daha yaxşıdır
}
Kitabxanalardakı ictimai inline funksiyalar ehtiyat tələb edir: inline funksiyanın gövdəsi dəyişərsə, bütün müştərilər yenidən kompilasiya etməlidir. JetBrains, modul daxilində uyğunluğu qorumaq üçün inline funksiyalardan çağrılan üzvlər üçün @PublishedApi internal istifadəsini tövsiyə edir.
Tez-tez verilən suallar
Bəli, inline extension function məhdudiyyətsiz işləyir. Məsələn: inline fun String.transform(block: (Char) -> Char): String. Genişləndirmə yerləşdirmə qabiliyyətinə təsir etmir — kompilator onu adi inline funksiya kimi emal edir.
Əgər funksiya lambda parametrləri qəbul etmirsə — inline üstünlük vermir. Kotlin kompilatoru xəbərdarlıq edir: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Həmçinin inline böyük funksiyalar üçün bayt-kodun artması səbəbindən zərərlidir.
inline — funksiyanın gövdəsini çağrı yerinə yerləşdirən funksiya modifikatorudur. @JvmInline (value class) — kompilasiya zamanı dəyərlə əvəz olunan sarğı sinifləri üçün mexanizmdir. Fərqli konsepsiyalar: inline çağrıları optimallaşdırır, value class məlumat təqdimatını optimallaşdırır.
Xeyr, suspend-funksiyalar inline ola bilməz, çünki onlar Continuation ilə vəziyyət maşınına kompilasiya olunur. Lakin inline funksiya crossinline ilə parametr kimi suspend-lambda qəbul edə bilər. Bu, korutinlərdə tez-tez istifadə olunur: inline fun launch(block: suspend CoroutineScope.() -> Unit).
Bəli, inline funksiyalar debug-u çətinləşdirir, çünki funksiyanın gövdəsi çağrılmır, əksinə çağrı yerinə yerləşdirilir. Stacktrace daha uzun olur, dayanma nöqtələri işləyir, lakin gözlənilməz mövqelər göstərə bilər. JetBrains inline olmadan debug etməyi və onu yalnız release qurğularında aktivləşdirməyi tövsiyə edir.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun