Storia della domanda:
Con la crescente popolarità della programmazione funzionale e delle espressioni lambda nella JVM, è emerso il problema dei costi di sovraccarico per gli oggetti anonimi e per le chiamate ai metodi aggiuntivi. In Java, questo si verifica con l'uso di interfacce funzionali. In Kotlin è stata introdotta la parola chiave inline per evitare allocazioni superflue nella trasmissione delle funzioni lambda.
Problema:
La chiamata a una funzione con parametri lambda crea oggetti anonimi nella heap e aumenta la profondità dello stack, il che rallenta l'esecuzione del codice, specialmente quando viene utilizzata attivamente in cicli e chiamate annidate.
Soluzione:
Kotlin consente di dichiarare una funzione con il modificatore inline, dopodiché il corpo della funzione e le lambda ad essa trasmesse vengono sostituite direttamente nel punto di chiamata durante la compilazione. Questo consente al compilatore di eliminare le allocazioni aggiuntive e migliorare le prestazioni, specialmente per funzioni brevi e frequentemente chiamate (ad esempio, filtraggio delle collezioni).
Esempio di codice:
inline fun <T> Iterable<T>.myFilter(predicate: (T) -> Boolean): List<T> { val result = mutableListOf<T>() for (item in this) if (predicate(item)) result.add(item) return result } val filtered = listOf(1, 2, 3, 4).myFilter { it % 2 == 0 } println(filtered) // [2, 4]
Caratteristiche chiave:
noinline e crossinline per controllare l'inlining di singole lambda.È possibile utilizzare la funzione inline con qualsiasi parametro funzionale o di tipo generico T?
No, le funzioni inline risparmiano principalmente sui costi di chiamata per i parametri lambda, ma il parametro generico stesso (ad esempio, T) non viene inlinato — per questo è necessario il modificatore reified. Per T semplici senza reified, le informazioni sul tipo verranno eliminate durante la fase di compilazione.
Cosa succede se dichiaro una chiusura su una variabile da uno scope esterno in una funzione inline?
Le variabili dallo scope esterno vengono copiate all'interno dell'espressione inlinata. Tutti gli accessi a queste variabili funzioneranno come se il codice fosse stato realmente sostituito. Questo può portare a comportamenti inaspettati se non ti aspetti effetti collaterali.
È possibile chiamare una funzione inline dal codice Java?
Sì, ma verrà compilata come una normale funzione, e il codice Java non vedrà alcun vantaggio dall'inlining. Kotlin ottiene ottimizzazione solo quando utilizzi le funzioni inline dal codice Kotlin.
return nelle lambda inline — controllo di flusso erratoUn sviluppatore inlina una funzione lunga con più lambda di filtraggio e post-elaborazione, sperando in un'accelerazione. Il codice compila a lungo, il file APK/RAR/DEX finale aumenta significativamente, e non c'è alcun guadagno in velocità.
Pro:
Contro:
È stata implementata una piccola funzione inline per filtri brevi di array, chiamata centinaia di volte in un ciclo caldo — il tempo di esecuzione è critico. La quantità di allocazioni di memoria è minima, poiché la lambda non crea un oggetto anonimo.
Pro:
Contro: