Contexte de la question :
Avec la croissance de la popularité de la programmation fonctionnelle et des expressions lambda sur la JVM, un problème est apparu concernant les frais généraux des objets anonymes et des appels de méthodes supplémentaires. En Java, cela se rencontre avec l'utilisation d'interfaces fonctionnelles. En Kotlin, le mot-clé inline a été introduit pour éviter les allocations inutiles lors du passage de fonctions lambda.
Problème :
L'appel d'une fonction avec des paramètres lambda crée des objets anonymes sur le tas et augmente la profondeur de la pile, ce qui ralentit l'exécution du code, surtout lorsqu'il est largement utilisé dans des boucles et des appels imbriqués.
Solution :
Kotlin permet de déclarer une fonction avec le modificateur inline, après quoi le corps de la fonction et les lambdas qui lui sont passées sont insérés directement à l'endroit appelé lors de la compilation. Cela permet au compilateur de se débarrasser des allocations supplémentaires et d'améliorer les performances, en particulier pour les fonctions courtes, souvent appelées (par exemple, le filtrage de collections).
Exemple de code :
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]
Caractéristiques clés :
noinline et crossinline pour contrôler l'inlining de lambdas spécifiques.Peut-on utiliser une fonction inline avec n'importe quel paramètre fonctionnel ou type générique T ?
Non, les fonctions inline économisent principalement sur les frais d'appel des paramètres lambda, mais le paramètre générique lui-même (par exemple, T) n'est pas inline — un modificateur reified est nécessaire. Pour des T simples sans reified, l'information de type sera effacée lors de la compilation.
Que se passera-t-il si, dans une fonction inline, une fermeture est déclarée sur une variable de l'espace de noms externe ?
Les variables de l'espace de noms externe sont copiées à l'intérieur de l'expression inline. Tous les accès à celles-ci fonctionneront comme si le code était réellement inséré. Cela peut conduire à un comportement inattendu si vous ne vous attendez pas à des effets secondaires.
Peut-on appeler une fonction inline depuis du code Java ?
Oui, mais elle sera compilée comme une fonction normale, et le code Java ne verra aucun avantage de l'inlining. Kotlin obtient une optimisation uniquement lorsque les fonctions inline sont utilisées à partir du code Kotlin.
return dans des lambdas inline — contrôle de flux incorrectUn développeur inline une longue fonction avec plusieurs lambdas de filtrage et de post-traitement, s'attendant à un gain de vitesse. Le code se compile longtemps, le fichier APK/RAR/DEX final augmente considérablement, sans amélioration de la vitesse.
Avantages :
Inconvénients :
Une petite fonction inline est mise en œuvre pour des filtres courts de tableau, appelée des centaines de fois dans une boucle chaude — le temps d'exécution est critique. Le nombre d'allocations mémoire est minimal, car la lambda ne crée pas d'objet anonyme.
Avantages :
Inconvénients :