fungsi inline — mekanisme Kotlin di mana tubuh fungsi disisipkan langsung ke setiap tempat pemanggilan pada tahap kompilasi. Ini menghilangkan overhead dari pembuatan kelas anonim dan objek untuk parameter lambda. Menurut Kotlin Documentation, 2025, kata kunci inline sangat efektif untuk fungsi higher-order, di mana setiap lambda tanpa penyisipan membuat objek FunctionN terpisah, membebani garbage collector.
Poin Utama
Fungsi inline adalah fungsi yang ditandai dengan kata kunci inline. Kompilator Kotlin tidak membuat bytecode terpisah dengan pemanggilan untuknya, tetapi menyalin tubuh fungsi langsung ke setiap tempat pemanggilan. Tujuan utama — optimasi fungsi higher-order yang menerima ekspresi lambda, karena setiap lambda dalam situasi normal membuat objek anonim dari kelas Function.
Menurut JetBrains Tech Blog (2024), penggunaan fungsi inline di Kotlin dapat mengurangi jumlah objek yang dibuat sebesar 40–60% pada fungsi yang secara intensif menggunakan lambda. Dalam perulangan dan operasi dengan beban tinggi (pengurutan, penyaringan koleksi) ini memberikan peningkatan kinerja yang terukur.
Tanpa inline, setiap lambda dikompilasi menjadi kelas anonim (atau instance dari antarmuka fungsional yang disintesis). Untuk lambda yang menangkap variabel, dibuat objek pembungkus tambahan. Fungsi inline menghilangkan semua objek ini pada tahap kompilasi, menggantinya dengan kode langsung dengan akses ke variabel lokal tanpa pembungkus.
Gunakan inline hanya untuk fungsi dengan parameter lambda — kompilator Kotlin sendiri memperingatkan jika inline tidak memberikan keuntungan.
Cukup tambahkan kata kunci inline sebelum deklarasi fungsi. Kompilator secara otomatis menyisipkan tubuh fungsi ke tempat pemanggilan. Fungsi itu sendiri tetap ada di bytecode untuk kasus ketika tidak dipanggil secara langsung (misalnya, dari kode Java).
inline fun Int.repeatAction(action: (Int) -> Unit) {
for (i in 0 until this) {
action(i)
}
}
// Panggilan — kode lambda disisipkan ke dalam tubuh fungsi
5.repeatAction { index ->
println("Index: $index")
}
Setelah kompilasi, kode di atas akan setara dengan:
// Apa yang terjadi setelah penyisipan (secara skematis):
val $this = 5
for (i in 0 until $this) {
println("Index: $i")
}
Tidak ada objek yang dibuat untuk lambda — kode action dijalankan langsung. Ini adalah inti dari optimasi: alih-alih pemanggilan Function.invoke() — penyisipan langsung kode dengan tubuh lambda.
Untuk memeriksa penyisipan, buka Tools > Kotlin > Show Kotlin Bytecode di IntelliJ IDEA dan klik Decompile. Anda akan melihat bahwa alih-alih pemanggilan repeatAction dengan lambda, penyisipan langsung tubuh fungsi dengan perulangan for dihasilkan.
Setiap lambda di Kotlin dikompilasi menjadi salah satu dari tiga varian. Pertama — jika lambda tidak menangkap variabel, ia menjadi metode statis dari kelas tempat ia dideklarasikan. Kedua — jika menangkap satu variabel, kelas anonim dibuat. Ketiga — jika menangkap beberapa variabel, kelas anonim dibuat dengan bidang untuk setiap variabel yang ditangkap.
| Tipe Lambda | Tanpa inline | Dengan inline |
|---|---|---|
| Tanpa tangkapan | Satu metode statis (digunakan kembali) | Penyisipan penuh, tanpa pemanggilan |
| Dengan tangkapan 1 variabel | Kelas anonim (satu objek) | Penyisipan penuh, tanpa objek |
| Dengan tangkapan N variabel | Kelas anonim dengan N bidang | Penyisipan penuh, tanpa objek |
| Rekursif | Pemanggilan biasa | inline dilarang |
Menurut Android Performance Patterns (Google, 2024), dalam aplikasi dengan penggunaan koleksi intensif (penyaringan, pengurutan, pengelompokan) fungsi inline mengurangi jumlah alokasi sebesar 25–35%. Efeknya sangat terlihat di Jetpack Compose, di mana setiap perubahan status menyebabkan komposisi ulang dengan banyak lambda.
Lambda dalam fungsi biasa tidak dapat melakukan return dari fungsi luar — hanya return lokal dari lambda itu sendiri (melalui return@label). Dalam fungsi inline, lambda disisipkan ke dalam tubuh fungsi pemanggil, sehingga nonlocal return menjadi mungkin: return di dalam lambda mengakhiri fungsi luar.
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 di lambda akan mengembalikan null dari processNumbers()
}
Nonlocal return nyaman untuk penghentian dini, tetapi dapat menyebabkan kesalahan. Jika lambda digunakan dalam konteks nonlokal (disimpan dalam variabel), nonlocal return akan menyebabkan RuntimeException. Kompilator Kotlin mengeluarkan peringatan saat mencoba penyimpanan semacam itu.
Ketika suatu fungsi memiliki beberapa parameter lambda, terkadang perlu menyisipkan hanya sebagian darinya. Untuk ini digunakan noinline — melarang penyisipan parameter lambda tertentu, membiarkannya sebagai objek Function biasa.
Modifikator crossinline memecahkan masalah sebaliknya: lambda disisipkan, tetapi nonlocal return dilarang. Ini diperlukan ketika lambda digunakan di dalam lambda lain atau dalam konteks di mana return tidak diizinkan (misalnya, diteruskan ke 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 dapat disimpan dalam variabel atau diteruskan ke tempat lain
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)
Dalam contoh, onSuccess ditandai sebagai crossinline — akan disisipkan, tetapi di dalamnya tidak dapat menggunakan return. onError ditandai sebagai noinline — tidak disisipkan, dapat diteruskan sebagai objek, disimpan di bidang kelas, atau digunakan sebagai listener.
Fungsi inline memiliki batasan. Fungsi rekursif inline dilarang — kompilator akan memberikan kesalahan. Fungsi inline tidak dapat memiliki visibilitas private atau internal jika dideklarasikan di modul lain, tetapi batasan ini terkait dengan akses, bukan dengan mekanisme penyisipan itu sendiri.
Ukuran bytecode bertambah dengan setiap pemanggilan fungsi inline, karena tubuhnya disalin. Menurut Kotlin Coding Conventions (JetBrains, 2025), disarankan menggunakan inline hanya untuk fungsi berukuran hingga 10–15 baris. Untuk fungsi besar, keuntungan dari penyisipan lambda dapat dinetralkan oleh peningkatan ukuran APK (di Android ini kritis — ada batas 64K metode).
// Praktik yang disarankan
inline fun withLock(lock: Lock, action: () -> T): T {
lock.lock()
try {
return action()
} finally {
lock.unlock()
}
}
// Tidak disarankan untuk fungsi besar
inline fun largeComputation(...) { // buruk — tubuh >50 baris
// lebih dari 50 baris — lebih baik diekstrak ke fungsi biasa
}
Fungsi inline publik di pustaka memerlukan kehati-hatian: jika tubuh fungsi inline berubah, semua klien harus mengompilasi ulang. JetBrains merekomendasikan penggunaan @PublishedApi internal untuk anggota yang dipanggil dari fungsi inline, untuk menjaga kompatibilitas dalam modul.
Pertanyaan yang Sering Diajukan
Ya, fungsi ekstensi inline bekerja tanpa batasan. Contoh: inline fun String.transform(block: (Char) -> Char): String. Ekstensi tidak memengaruhi kemampuan penyisipan — kompilator memprosesnya seperti fungsi inline biasa.
Jika fungsi tidak menerima parameter lambda — inline tidak memberikan keuntungan. Kompilator Kotlin mengeluarkan peringatan: "Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types." Juga inline berbahaya untuk fungsi besar karena pertumbuhan bytecode.
inline — pengubah fungsi yang menyisipkan tubuhnya ke tempat pemanggilan. @JvmInline (value class) — mekanisme untuk kelas pembungkus yang diganti dengan nilai selama kompilasi. Konsep berbeda: inline mengoptimalkan pemanggilan, value class mengoptimalkan representasi data.
Tidak, fungsi suspend tidak bisa inline, karena dikompilasi menjadi mesin status dengan Continuation. Namun, fungsi inline dapat menerima lambda suspend sebagai parameter dengan crossinline. Ini sering digunakan di coroutine: inline fun launch(block: suspend CoroutineScope.() -> Unit).
Ya, fungsi inline mempersulit debugging, karena tubuh fungsi tidak dipanggil, melainkan disisipkan ke tempat pemanggilan. Stacktrace menjadi lebih panjang, titik henti berfungsi tetapi dapat menunjukkan posisi yang tidak terduga. JetBrains merekomendasikan debugging tanpa inline, dan mengaktifkannya hanya di build release.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga