इनलाइन फंक्शन — Kotlin तंत्र जिसमें फंक्शन का बॉडी संकलन समय पर सीधे प्रत्येक कॉल स्थान पर प्रतिस्थापित हो जाता है। यह लैम्ब्डा पैरामीटर के लिए अनाम क्लास और ऑब्जेक्ट बनाने के ओवरहेड को समाप्त करता है। Kotlin Documentation, 2025 के अनुसार, inline कीवर्ड उच्च-क्रम फंक्शन के लिए विशेष रूप से प्रभावी है, जहाँ प्रत्येक लैम्ब्डा इनलाइनिंग के बिना एक अलग FunctionN ऑब्जेक्ट बनाता है, जिससे गार्बेज कलेक्टर पर भार बढ़ता है।
मुख्य बिंदु
इनलाइन फंक्शन एक फंक्शन है जो inline कीवर्ड से चिह्नित होता है। Kotlin संकलक इसके लिए अलग बाइटकोड नहीं बनाता — बल्कि फंक्शन के बॉडी को सीधे प्रत्येक कॉल स्थान पर कॉपी करता है। मुख्य उद्देश्य उच्च-क्रम फंक्शन को ऑप्टिमाइज़ करना है जो लैम्ब्डा एक्सप्रेशन स्वीकार करते हैं, क्योंकि सामान्य स्थिति में प्रत्येक लैम्ब्डा एक अनाम Function क्लास ऑब्जेक्ट बनाता है।
JetBrains Tech Blog (2024) के अनुसार, Kotlin में इनलाइन फंक्शन का उपयोग उन फंक्शन में बनाए गए ऑब्जेक्ट की संख्या को 40–60% तक कम कर सकता है जो लैम्ब्डा का गहन उपयोग करते हैं। लूप और उच्च-लोड संचालन (सॉर्टिंग, कलेक्शन फ़िल्टरिंग) में यह मापने योग्य प्रदर्शन लाभ प्रदान करता है।
Inline के बिना, प्रत्येक लैम्ब्डा एक अनाम क्लास (या संश्लेषित कार्यात्मक इंटरफ़ेस के इंस्टेंस) में संकलित होता है। वेरिएबल कैप्चर करने वाले लैम्ब्डा के लिए, अतिरिक्त रैपर ऑब्जेक्ट बनाए जाते हैं। इनलाइन फंक्शन संकलन समय पर इन सभी ऑब्जेक्ट को समाप्त कर देते हैं, उन्हें बिना रैपर के स्थानीय वेरिएबल तक पहुँचने वाले सीधे कोड से बदल देते हैं।
Inline का उपयोग केवल लैम्ब्डा पैरामीटर वाले फंक्शन के लिए करें — Kotlin संकलक स्वयं चेतावनी देता है यदि inline कोई लाभ प्रदान नहीं करता है।
बस फंक्शन घोषणा से पहले inline कीवर्ड जोड़ें। संकलक स्वचालित रूप से कॉल स्थानों पर फंक्शन बॉडी को प्रतिस्थापित करता है। फंक्शन स्वयं बाइटकोड में उन मामलों के लिए मौजूद रहता है जब इसे सीधे नहीं बुलाया जाता (उदाहरण के लिए, Java कोड से)।
inline fun Int.repeatAction(action: (Int) -> Unit) {
for (i in 0 until this) {
action(i)
}
}
// कॉल — लैम्ब्डा कोड फंक्शन बॉडी में इनलाइन हो जाता है
5.repeatAction { index ->
println("Index: $index")
}
संकलन के बाद, उपरोक्त कोड इसके बराबर होगा:
// इनलाइनिंग के बाद क्या होता है (योजनाबद्ध रूप से):
val $this = 5
for (i in 0 until $this) {
println("Index: $i")
}
लैम्ब्डा के लिए कोई ऑब्जेक्ट नहीं बनाया जाता — एक्शन कोड सीधे निष्पादित होता है। यही ऑप्टिमाइज़ेशन का सार है: Function.invoke() को कॉल करने के बजाय — लैम्ब्डा बॉडी के साथ कोड का सीधा सम्मिलन।
इनलाइनिंग को सत्यापित करने के लिए, IntelliJ IDEA में Tools > Kotlin > Show Kotlin Bytecode खोलें और Decompile पर क्लिक करें। आप देखेंगे कि लैम्ब्डा के साथ repeatAction को कॉल करने के बजाय, for लूप के साथ फंक्शन बॉडी का सीधा सम्मिलन उत्पन्न होता है।
Kotlin में प्रत्येक लैम्ब्डा तीन वेरिएंट में से एक में संकलित होता है। पहला — यदि लैम्ब्डा वेरिएबल कैप्चर नहीं करता, तो यह उस क्लास की स्थैतिक विधि बन जाता है जहाँ इसे घोषित किया गया है। दूसरा — यदि यह एक वेरिएबल कैप्चर करता है, तो एक अनाम क्लास बनाई जाती है। तीसरा — यदि यह कई वेरिएबल कैप्चर करता है, तो प्रत्येक कैप्चर किए गए वेरिएबल के लिए फ़ील्ड वाली एक अनाम क्लास बनाई जाती है।
| लैम्ब्डा प्रकार | Inline के बिना | Inline के साथ |
|---|---|---|
| बिना कैप्चर | एक स्थैतिक विधि (पुनः उपयोग) | पूर्ण इनलाइनिंग, बिना कॉल |
| 1 वेरिएबल कैप्चर | अनाम क्लास (एक ऑब्जेक्ट) | पूर्ण इनलाइनिंग, बिना ऑब्जेक्ट |
| N वेरिएबल कैप्चर | N फ़ील्ड वाली अनाम क्लास | पूर्ण इनलाइनिंग, बिना ऑब्जेक्ट |
| पुनरावर्ती | सामान्य कॉल | inline निषिद्ध |
Android Performance Patterns (Google, 2024) के अनुसार, कलेक्शन के गहन उपयोग वाले एप्लिकेशन (फ़िल्टरिंग, सॉर्टिंग, ग्रुपिंग) में इनलाइन फंक्शन आवंटन को 25–35% तक कम करते हैं। प्रभाव विशेष रूप से Jetpack Compose में ध्यान देने योग्य है, जहाँ प्रत्येक स्थिति परिवर्तन कई लैम्ब्डा के साथ पुनर्संरचना को ट्रिगर करता है।
सामान्य फंक्शन में लैम्ब्डा बाहरी फंक्शन से return नहीं कर सकता — केवल लैम्ब्डा से स्थानीय return (return@label के माध्यम से)। इनलाइन फंक्शन में, लैम्ब्डा कॉल करने वाले फंक्शन के बॉडी में इनलाइन हो जाता है, इसलिए नॉनलोकल रिटर्न संभव हो जाता है: लैम्ब्डा के अंदर return बाहरी फंक्शन को समाप्त कर देता है।
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 processNumbers() से null लौटाएगा
}
नॉनलोकल रिटर्न शीघ्र समाप्ति के लिए सुविधाजनक है, लेकिन त्रुटियों का कारण बन सकता है। यदि लैम्ब्डा का उपयोग गैर-स्थानीय संदर्भ में किया जाता है (एक वेरिएबल में संग्रहीत), तो नॉनलोकल रिटर्न RuntimeException का कारण बनेगा। Kotlin संकलक ऐसे भंडारण का प्रयास करने पर चेतावनी जारी करता है।
जब किसी फंक्शन में कई लैम्ब्डा पैरामीटर होते हैं, तो कभी-कभी केवल उनमें से कुछ को इनलाइन करने की आवश्यकता होती है। इसके लिए noinline का उपयोग किया जाता है — यह किसी विशिष्ट लैम्ब्डा पैरामीटर के इनलाइनिंग को रोकता है, इसे सामान्य Function ऑब्जेक्ट के रूप में छोड़ता है।
crossinline मॉडिफ़ायर विपरीत समस्या हल करता है: लैम्ब्डा इनलाइन होता है, लेकिन नॉनलोकल रिटर्न निषिद्ध होता है। यह तब आवश्यक है जब लैम्ब्डा का उपयोग किसी अन्य लैम्ब्डा के अंदर या ऐसे संदर्भ में किया जाता है जहाँ return की अनुमति नहीं है (उदाहरण के लिए, 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 को वेरिएबल में संग्रहीत या कहीं और पास किया जा सकता है
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)
उदाहरण में, onSuccess को crossinline के रूप में चिह्नित किया गया है — यह इनलाइन होगा, लेकिन इसके अंदर return का उपयोग नहीं किया जा सकता। onError को noinline के रूप में चिह्नित किया गया है — यह इनलाइन नहीं होता, इसलिए इसे ऑब्जेक्ट के रूप में पास किया जा सकता है, क्लास फ़ील्ड में संग्रहीत किया जा सकता है, या लिसनर के रूप में उपयोग किया जा सकता है।
इनलाइन फंक्शन की सीमाएँ हैं। पुनरावर्ती इनलाइन फंक्शन निषिद्ध हैं — संकलक त्रुटि लौटाएगा। इनलाइन फंक्शन में private या internal दृश्यता नहीं हो सकती यदि वे किसी अन्य मॉड्यूल में घोषित किए गए हैं, लेकिन यह दृश्यता सीमा है, इनलाइनिंग तंत्र से संबंधित नहीं।
प्रत्येक इनलाइन फंक्शन कॉल के साथ बाइटकोड आकार बढ़ता है, क्योंकि बॉडी कॉपी की जाती है। Kotlin Coding Conventions (JetBrains, 2025) के अनुसार, inline का उपयोग केवल 10–15 पंक्तियों तक के फंक्शन के लिए करने की अनुशंसा की जाती है। बड़े फंक्शन के लिए, लैम्ब्डा इनलाइनिंग का लाभ APK आकार में वृद्धि से नकारा जा सकता है (Android में 64K विधि सीमा के कारण महत्वपूर्ण)।
// अनुशंसित अभ्यास
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 fun String.transform(block: (Char) -> Char): String। एक्सटेंशन इनलाइन करने की क्षमता को प्रभावित नहीं करता — संकलक इसे सामान्य इनलाइन फंक्शन की तरह ही संभालता है।
यदि फंक्शन लैम्ब्डा पैरामीटर स्वीकार नहीं करता — inline कोई लाभ प्रदान नहीं करता। Kotlin संकलक चेतावनी जारी करता है: “Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types.” साथ ही, बाइटकोड वृद्धि के कारण inline बड़े फंक्शन के लिए हानिकारक है।
inline — एक फंक्शन मॉडिफ़ायर जो फंक्शन बॉडी को कॉल स्थान पर इनलाइन करता है। @JvmInline (value class) — रैपर क्लास के लिए तंत्र जो संकलन समय पर उनके मान से बदल दिए जाते हैं। अलग अवधारणाएँ: inline कॉल को ऑप्टिमाइज़ करता है, value class डेटा प्रतिनिधित्व को ऑप्टिमाइज़ करता है।
नहीं, suspend फंक्शन inline नहीं हो सकते क्योंकि वे Continuation के साथ स्टेट मशीन में संकलित होते हैं। हालांकि, एक इनलाइन फंक्शन crossinline के साथ पैरामीटर के रूप में suspend लैम्ब्डा स्वीकार कर सकता है। इसका उपयोग अक्सर कोरूटीन में किया जाता है: inline fun launch(block: suspend CoroutineScope.() -> Unit).
हाँ, इनलाइन फंक्शन डीबगिंग को जटिल बनाते हैं क्योंकि फंक्शन बॉडी को कॉल नहीं किया जाता बल्कि कॉल स्थान पर इनलाइन किया जाता है। स्टैकट्रेस लंबे हो जाते हैं, ब्रेकपॉइंट काम करते हैं लेकिन अप्रत्याशित स्थान दिखा सकते हैं। JetBrains बिना inline के डीबग करने और केवल release बिल्ड में इसे सक्षम करने की अनुशंसा करता है।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें