Inline function in Kotlin: cos'è, sintassi e utilizzo

Autore: IT Sectr Pubblicato: 2026-06-21 Tempo di lettura: 9 min

inline function — un meccanismo Kotlin in cui il corpo della funzione viene sostituito direttamente in ogni punto di chiamata in fase di compilazione. Ciò elimina l'overhead derivante dalla creazione di classi anonime e oggetti per i parametri lambda. Secondo Kotlin Documentation, 2025, la parola chiave inline è particolarmente efficace per le funzioni di ordine superiore, dove ogni lambda senza inserimento crea un oggetto FunctionN separato, appesantendo il garbage collector.

Punti chiave

  • funzione inline — funzione il cui corpo viene inserito nel punto di chiamata in fase di compilazione
  • Riduzione overhead — elimina la creazione di classi anonime e oggetti per le lambda
  • Nonlocal return — le lambda all'interno di funzioni inline possono restituire dalla funzione esterna
  • noinline — impedisce l'inserimento di parametri lambda specifici
  • crossinline — consente il nonlocal return ma proibisce il return dal contesto della funzione inline

Cos'è una inline function in Kotlin?

Una funzione inline è una funzione contrassegnata dalla parola chiave inline. Il compilatore Kotlin non crea bytecode separato con una chiamata per essa — invece, copia direttamente il corpo della funzione in ogni punto di chiamata. L'obiettivo principale è ottimizzare le funzioni di ordine superiore che accettano espressioni lambda, poiché ogni lambda in una situazione normale crea un oggetto di classe Function anonimo.

Secondo JetBrains Tech Blog (2024), l'uso di funzioni inline in Kotlin può ridurre il numero di oggetti creati del 40–60% nelle funzioni che utilizzano intensivamente le lambda. Nei cicli e nelle operazioni ad alto carico (ordinamento, filtraggio di collezioni) ciò fornisce un miglioramento delle prestazioni misurabile.

Senza inline, ogni lambda viene compilata in una classe anonima (o un'istanza di un'interfaccia funzionale sintetizzata). Per le lambda che catturano variabili, vengono creati oggetti wrapper aggiuntivi. Le funzioni inline eliminano tutti questi oggetti in fase di compilazione, sostituendoli con codice diretto che accede alle variabili locali senza wrapper.

Utilizza inline solo per funzioni con parametri lambda — il compilatore Kotlin avverte se inline non fornisce benefici.

Sintassi della inline function e funzionamento

Basta aggiungere la parola chiave inline prima della dichiarazione della funzione. Il compilatore sostituisce automaticamente il corpo della funzione nei punti di chiamata. La funzione stessa continua ad esistere in bytecode per i casi in cui non viene chiamata direttamente (ad esempio, da codice Java).

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

// Chiamata — il codice lambda viene inserito nel corpo della funzione
5.repeatAction { index ->
    println("Index: $index")
}

Dopo la compilazione, il codice sopra sarà equivalente a:

kotlin
// Cosa succede dopo l'inserimento (schematizzato):
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

Nessun oggetto viene creato per la lambda — il codice action viene eseguito direttamente. Questa è l'essenza dell'ottimizzazione: invece di chiamare Function.invoke() — un inserimento diretto del codice con il corpo della lambda.

Verifica tramite decompilazione

Per verificare l'inserimento, apri Tools > Kotlin > Show Kotlin Bytecode in IntelliJ IDEA e fai clic su Decompile. Vedrai che invece di chiamare repeatAction con una lambda, viene generato un inserimento diretto del corpo della funzione con un ciclo for.

Il problema dell'overhead delle lambda e la sua soluzione

Ogni lambda in Kotlin viene compilata in una delle tre varianti. Prima — se la lambda non cattura variabili, diventa un metodo statico della classe in cui è dichiarata. Seconda — se cattura una variabile, viene creata una classe anonima. Terza — se cattura più variabili, viene creata una classe anonima con campi per ogni variabile catturata.

Tipo di lambdaSenza inlineCon inline
Senza catturaUn metodo statico (riutilizzato)Inserimento completo, senza chiamata
Con cattura di 1 variabileClasse anonima (un oggetto)Inserimento completo, senza oggetto
Con cattura di N variabiliClasse anonima con N campiInserimento completo, senza oggetto
RicorsivaChiamata normaleinline vietato

Secondo Android Performance Patterns (Google, 2024), nelle applicazioni con uso intensivo di collezioni (filtraggio, ordinamento, raggruppamento) le funzioni inline riducono le allocazioni del 25–35%. L'effetto è particolarmente evidente in Jetpack Compose, dove ogni cambiamento di stato attiva una ricomposizione con molte lambda.

Nonlocal return e limitazioni

Una lambda in una funzione normale non può restituire dalla funzione esterna — solo un return locale dalla lambda stessa (tramite return@label). In una funzione inline, la lambda viene inserita nel corpo della funzione chiamante, quindi nonlocal return diventa possibile: un return all'interno della lambda termina la funzione esterna.

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 nella lambda restituirebbe null da processNumbers()
}

Nonlocal return è comodo per la terminazione anticipata, ma può causare errori. Se la lambda viene utilizzata in un contesto non locale (memorizzata in una variabile), un nonlocal return causerà una RuntimeException. Il compilatore Kotlin emette un avviso quando si tenta tale memorizzazione.

noinline e crossinline: controllo dell'inserimento

Quando una funzione ha più parametri lambda, a volte è necessario inserire solo alcuni di essi. Per questo si usa noinline — impedisce l'inserimento di un parametro lambda specifico, lasciandolo come un normale oggetto Function.

Il modificatore crossinline risolve il problema opposto: la lambda viene inserita, ma il nonlocal return è vietato. Ciò è necessario quando la lambda viene utilizzata all'interno di un'altra lambda o in un contesto in cui return non è consentito (ad esempio, passato a un 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 può essere memorizzato in una variabile o passato altrove
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

Nell'esempio, onSuccess è contrassegnata come crossinline — verrà inserita, ma non è possibile utilizzare return al suo interno. onError è contrassegnata come noinline — non viene inserita, quindi può essere passata come oggetto, memorizzata in un campo di classe o utilizzata come listener.

Limitazioni delle funzioni inline e raccomandazioni

Le funzioni inline hanno limitazioni. Le funzioni inline ricorsive sono vietate — il compilatore restituirà un errore. Le funzioni inline non possono avere visibilità private o internal se dichiarate in un altro modulo, ma questa è una limitazione di visibilità, non correlata al meccanismo di inserimento stesso.

La dimensione del bytecode cresce con ogni chiamata a funzione inline, poiché il corpo viene copiato. Secondo Kotlin Coding Conventions (JetBrains, 2025), si raccomanda di usare inline solo per funzioni fino a 10–15 righe. Per funzioni grandi, il beneficio dell'inserimento delle lambda può essere annullato dall'aumento delle dimensioni dell'APK (critico su Android a causa del limite di 64K metodi).

kotlin
// Pratica consigliata
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// Non consigliato per funzioni grandi
inline fun largeComputation(...) { // male — corpo >50 righe
    // più di 50 righe — meglio estrarre in una funzione regolare
}

Le funzioni inline pubbliche nelle librerie richiedono cautela: se il corpo di una funzione inline cambia, tutti i client devono essere ricompilati. JetBrains raccomanda di usare @PublishedApi internal per i membri chiamati da funzioni inline per mantenere la compatibilità all'interno di un modulo.

Domande frequenti

Si può creare una funzione di estensione inline?

, una funzione di estensione inline funziona senza restrizioni. Ad esempio: inline fun String.transform(block: (Char) -> Char): String. L'estensione non influisce sulla capacità di inserimento — il compilatore la tratta come una normale funzione inline.

Quando inline NON fornisce vantaggi?

Se la funzione non accetta parametri lambda — inline non fornisce vantaggi. Il compilatore Kotlin emette un avviso: “Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types.” Inoltre, inline è dannoso per funzioni grandi a causa della crescita del bytecode.

Come si differenzia inline da @JvmInline (value class)?

inline — un modificatore di funzione che inserisce il corpo della funzione nel punto di chiamata. @JvmInline (value class) — un meccanismo per classi wrapper che vengono sostituite dal loro valore in fase di compilazione. Concetti diversi: inline ottimizza le chiamate, value class ottimizza la rappresentazione dei dati.

Si può usare inline con funzioni suspend?

No, le funzioni suspend non possono essere inline perché vengono compilate in una macchina a stati con Continuation. Tuttavia, una funzione inline può accettare una lambda suspend come parametro con crossinline. Questo viene spesso usato nelle coroutine: inline fun launch(block: suspend CoroutineScope.() -> Unit).

Inline influisce sul debug?

, le funzioni inline complicano il debug perché il corpo della funzione non viene chiamato ma inserito nel punto di chiamata. Gli stacktrace diventano più lunghi, i breakpoint funzionano ma possono mostrare posizioni inaspettate. JetBrains raccomanda di eseguire il debug senza inline e di abilitarlo solo nelle build release.

Riepilogo

  • funzione inline — inserisce il corpo della funzione nel punto di chiamata, eliminando l'overhead delle lambda
  • Nonlocal return — return da una lambda termina la funzione esterna (possibile solo con inline)
  • noinline — impedisce l'inserimento di un parametro lambda specifico
  • crossinline — consente l'inserimento ma vieta il nonlocal return
  • Funzioni ricorsive non possono essere inline — il compilatore restituisce un errore
  • Dimensione del bytecode cresce — usa inline per funzioni fino a 10–15 righe
  • Utilizzo ottimale — funzioni di ordine superiore con parametri lambda, blocchi di sincronizzazione, scope functions (let, apply, also, run)

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche