Inline function en Kotlin : définition, syntaxe et utilisation

Auteur : IT Sectr Publié le : 2026-06-21 Temps de lecture : 9 min

inline function — un mécanisme Kotlin où le corps de la fonction est substitué directement à chaque site d'appel au moment de la compilation. Cela élimine la surcharge liée à la création de classes anonymes et d'objets pour les paramètres lambda. Selon Kotlin Documentation, 2025, le mot-clé inline est particulièrement efficace pour les fonctions d'ordre supérieur, où chaque lambda sans insertion crée un objet FunctionN séparé, alourdissant le ramasse-miettes.

Points clés

  • fonction inline — fonction dont le corps est inséré au site d'appel au moment de la compilation
  • Réduction de surcharge — élimine la création de classes anonymes et d'objets pour les lambdas
  • Nonlocal return — les lambdas dans les fonctions inline peuvent retourner depuis la fonction externe
  • noinline — empêche l'insertion de paramètres lambda spécifiques
  • crossinline — autorise le nonlocal return mais interdit le return depuis le contexte de la fonction inline

Qu'est-ce qu'une inline function en Kotlin ?

Une fonction inline est une fonction marquée par le mot-clé inline. Le compilateur Kotlin ne crée pas de bytecode séparé avec un appel pour celle-ci — il copie plutôt le corps de la fonction directement à chaque site d'appel. L'objectif principal est d'optimiser les fonctions d'ordre supérieur qui acceptent des expressions lambda, car chaque lambda dans une situation normale crée un objet de classe Function anonyme.

Selon le JetBrains Tech Blog (2024), l'utilisation de fonctions inline en Kotlin peut réduire le nombre d'objets créés de 40 à 60 % dans les fonctions qui utilisent intensivement les lambdas. Dans les boucles et les opérations à forte charge (tri, filtrage de collections), cela offre un gain de performances mesurable.

Sans inline, chaque lambda se compile en une classe anonyme (ou une instance d'une interface fonctionnelle synthétisée). Pour les lambdas qui capturent des variables, des objets wrapper supplémentaires sont créés. Les fonctions inline éliminent tous ces objets au moment de la compilation, les remplaçant par du code direct qui accède aux variables locales sans wrappers.

Utilisez inline uniquement pour les fonctions avec des paramètres lambda — le compilateur Kotlin prévient lui-même si inline n'apporte aucun avantage.

Syntaxe de l'inline function et fonctionnement

Ajoutez simplement le mot-clé inline avant la déclaration de la fonction. Le compilateur substitue automatiquement le corps de la fonction aux sites d'appel. La fonction elle-même continue d'exister en bytecode pour les cas où elle n'est pas appelée directement (par exemple, depuis du code Java).

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

// Appel — le code lambda est inséré dans le corps de la fonction
5.repeatAction { index ->
    println("Index: $index")
}

Après compilation, le code ci-dessus sera équivalent à :

kotlin
// Ce qui se passe après l'insertion (schématiquement) :
val $this = 5
for (i in 0 until $this) {
    println("Index: $i")
}

Aucun objet n'est créé pour le lambda — le code action s'exécute directement. C'est l'essence de l'optimisation : au lieu d'appeler Function.invoke() — une insertion directe du code avec le corps du lambda.

Vérification par décompilation

Pour vérifier l'insertion, ouvrez Tools > Kotlin > Show Kotlin Bytecode dans IntelliJ IDEA et cliquez sur Decompile. Vous verrez qu'au lieu d'appeler repeatAction avec un lambda, une insertion directe du corps de la fonction avec une boucle for est générée.

Le problème de la surcharge des lambdas et sa solution

Chaque lambda en Kotlin se compile en l'une des trois variantes. Première — si le lambda ne capture pas de variables, il devient une méthode statique de la classe dans laquelle il est déclaré. Deuxième — s'il capture une variable, une classe anonyme est créée. Troisième — s'il capture plusieurs variables, une classe anonyme avec des champs pour chaque variable capturée est créée.

Type de lambdaSans inlineAvec inline
Sans captureUne méthode statique (réutilisée)Insertion complète, sans appel
Avec capture d'1 variableClasse anonyme (un objet)Insertion complète, sans objet
Avec capture de N variablesClasse anonyme avec N champsInsertion complète, sans objet
RécursifAppel normalinline interdit

Selon Android Performance Patterns (Google, 2024), dans les applications utilisant intensivement les collections (filtrage, tri, regroupement), les fonctions inline réduisent les allocations de 25 à 35 %. L'effet est particulièrement notable dans Jetpack Compose, où chaque changement d'état déclenche une recomposition avec de nombreuses lambdas.

Nonlocal return et limitations

Un lambda dans une fonction normale ne peut pas retourner depuis la fonction externe — seulement un retour local depuis le lambda lui-même (via return@label). Dans une fonction inline, le lambda est inséré dans le corps de la fonction appelante, donc nonlocal return devient possible : un return à l'intérieur du lambda termine la fonction externe.

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 dans le lambda retournerait null depuis processNumbers()
}

Nonlocal return est pratique pour une terminaison anticipée, mais peut provoquer des erreurs. Si le lambda est utilisé dans un contexte non local (stocké dans une variable), un nonlocal return entraînera une RuntimeException. Le compilateur Kotlin émet un avertissement lors d'une tentative de ce stockage.

noinline et crossinline : contrôle de l'insertion

Lorsqu'une fonction a plusieurs paramètres lambda, il est parfois nécessaire d'insérer seulement certains d'entre eux. Pour cela, on utilise noinline — il empêche l'insertion d'un paramètre lambda spécifique, le laissant comme un objet Function normal.

Le modificateur crossinline résout le problème inverse : le lambda est inséré, mais le nonlocal return est interdit. Cela est nécessaire lorsque le lambda est utilisé à l'intérieur d'un autre lambda ou dans un contexte où return n'est pas autorisé (par exemple, passé à 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 peut être stocké dans une variable ou passé ailleurs
val errorHandler = { e: Exception -> log(e.message) }
processWithCallback("input", { println(it) }, errorHandler)

Dans l'exemple, onSuccess est marquée comme crossinline — elle sera insérée, mais on ne peut pas utiliser return à l'intérieur. onError est marquée comme noinline — elle n'est pas insérée, donc elle peut être passée comme objet, stockée dans un champ de classe ou utilisée comme listener.

Limitations des fonctions inline et recommandations

Les fonctions inline ont des limitations. Les fonctions inline récursives sont interdites — le compilateur renverra une erreur. Les fonctions inline ne peuvent pas avoir de visibilité private ou internal si elles sont déclarées dans un autre module, mais c'est une limitation de visibilité, non liée au mécanisme d'insertion lui-même.

La taille du bytecode augmente à chaque appel de fonction inline, car le corps est copié. Selon Kotlin Coding Conventions (JetBrains, 2025), il est recommandé d'utiliser inline uniquement pour les fonctions de 10 à 15 lignes maximum. Pour les grandes fonctions, le bénéfice de l'insertion des lambdas peut être annulé par l'augmentation de la taille de l'APK (critique sur Android en raison de la limite de 64K méthodes).

kotlin
// Pratique recommandée
inline fun withLock(lock: Lock, action: () -> T): T {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// Non recommandé pour les grandes fonctions
inline fun largeComputation(...) { // mauvais — corps >50 lignes
    // plus de 50 lignes — mieux vaut extraire dans une fonction régulière
}

Les fonctions inline publiques dans les bibliothèques nécessitent de la prudence : si le corps d'une fonction inline change, tous les clients doivent être recompilés. JetBrains recommande d'utiliser @PublishedApi internal pour les membres appelés depuis des fonctions inline afin de maintenir la compatibilité au sein d'un module.

Questions fréquentes

Peut-on créer une fonction d'extension inline ?

Oui, une fonction d'extension inline fonctionne sans restrictions. Par exemple : inline fun String.transform(block: (Char) -> Char): String. L'extension n'affecte pas la capacité d'insertion — le compilateur la traite comme une fonction inline normale.

Quand inline n'apporte-t-il AUCUN avantage ?

Si la fonction n'accepte pas de paramètres lambda — inline n'apporte aucun avantage. Le compilateur Kotlin émet un avertissement : « Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types. » De plus, inline est nuisible pour les grandes fonctions en raison de la croissance du bytecode.

En quoi inline diffère-t-il de @JvmInline (value class) ?

inline — un modificateur de fonction qui insère le corps de la fonction au site d'appel. @JvmInline (value class) — un mécanisme pour les classes wrapper qui sont remplacées par leur valeur au moment de la compilation. Concepts différents : inline optimise les appels, value class optimise la représentation des données.

Peut-on utiliser inline avec les fonctions suspend ?

Non, les fonctions suspend ne peuvent pas être inline car elles se compilent en une machine d'état avec Continuation. Cependant, une fonction inline peut accepter un lambda suspend comme paramètre avec crossinline. Cela est souvent utilisé dans les coroutines : inline fun launch(block: suspend CoroutineScope.() -> Unit).

Inline affecte-t-il le débogage ?

Oui, les fonctions inline compliquent le débogage car le corps de la fonction n'est pas appelé mais inséré au site d'appel. Les traces de pile deviennent plus longues, les points d'arrêt fonctionnent mais peuvent montrer des positions inattendues. JetBrains recommande de déboguer sans inline et de l'activer uniquement dans les versions release.

Résumé

  • fonction inline — insère le corps de la fonction au site d'appel, éliminant la surcharge des lambdas
  • Nonlocal return — return depuis un lambda termine la fonction externe (possible uniquement avec inline)
  • noinline — empêche l'insertion d'un paramètre lambda spécifique
  • crossinline — permet l'insertion mais interdit le nonlocal return
  • Fonctions récursives ne peuvent pas être inline — le compilateur renvoie une erreur
  • Taille du bytecode augmente — utilisez inline pour les fonctions de 10 à 15 lignes maximum
  • Utilisation optimale — fonctions d'ordre supérieur avec paramètres lambda, blocs de synchronisation, fonctions de portée (let, apply, also, run)

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi