extension function — un mécanisme Kotlin qui permet d'ajouter de nouvelles méthodes aux classes existantes sans héritage et sans modifier le code source. La fonction est déclarée avec un préfixe sous la forme d'un type récepteur et est appelée comme une méthode normale de ce type. Selon Kotlin Documentation, 2025, les extension functions sont compilées en méthodes statiques avec le récepteur comme premier paramètre, ce qui garantit zéro surcharge à l'exécution par rapport aux appels normaux.
Points clés
Une extension function est une fonction déclarée en dehors d'une classe mais appelée comme sa méthode. Elle prend un type récepteur auquel la nouvelle méthode est ajoutée. À l'intérieur de la fonction, le mot-clé this fait référence à l'instance du type récepteur. Cette approche permet d'étendre les classes finales, les classes de bibliothèques tierces et même les types primitifs sans créer de wrappers.
Contrairement à Java, où ajouter une méthode à une classe existante nécessite soit l'héritage, soit une classe utilitaire statique, Kotlin offre une solution élégante sans boilerplate. Selon une étude de la Kotlin Foundation (2024), les extension functions font partie des cinq fonctionnalités les plus utilisées du langage — 78 % des développeurs Kotlin les utilisent dans leur travail quotidien.
Le compilateur Kotlin traduit une extension function en une méthode statique où l'instance du récepteur est passée comme premier argument. Cela signifie que les extension functions ne modifient pas le bytecode de la classe cible et ne brisent pas l'encapsulation — seuls les champs et méthodes publics du récepteur sont accessibles.
Utilisez les extension functions pour écrire des fonctions utilitaires propres qui sont logiquement liées à un type spécifique mais ne peuvent pas être ajoutées à son code source.
La syntaxe de base d'une extension function : le nom du type récepteur, un point, le nom de la fonction, puis les paramètres et le type de retour. À l'intérieur de la fonction, le récepteur est accessible via this.
// Extension function for String
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Called as regular String method
val result = "user@example.com".isEmail() // true
Dans cet exemple, isEmail() devient disponible pour toutes les chaînes. À l'intérieur de la fonction, this fait référence à la chaîne elle-même sur laquelle la méthode est appelée. Kotlin permet d'omettre this dans la plupart des cas — on peut simplement écrire contains("@") au lieu de this.contains("@").
Les extension functions peuvent accepter des paramètres supplémentaires et retourner des valeurs de n'importe quel type. Cela en fait des fonctions à part entière, pas seulement du sucre syntaxique.
fun List<Int>.defaultIfEmpty(default: Int): List<Int> {
if (this.isEmpty()) return listOf(default)
return this
}
val populated = listOf(1, 2).defaultIfEmpty(0)
val empty = listOf<Int>().defaultIfEmpty(0)
Le paramètre default définit la valeur retournée pour une liste vide. Une extension function peut être générique — le type List
Les extension functions en Kotlin utilisent le dispatch statique, pas le dispatch virtuel. C'est une différence clé par rapport aux méthodes de classe normales. Quelle extension function est appelée est déterminée à la compilation par le type statique de la variable, pas par son type réel à l'exécution.
open class Animal
class Dog : Animal()
fun Animal.speak() = "Animal sound"
fun Dog.speak() = "Woof"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // "Animal sound" — static type Animal
val dog: Dog = Dog()
println(dog.speak()) // "Woof" — static type Dog
}
Même si la variable animal pointe vers une instance de Dog, l'extension function pour Animal est appelée car le type statique de la variable est Animal. Si speak() était une méthode virtuelle de classe, Dog.speak() aurait été appelée. Ce comportement est important à prendre en compte lors de la conception d'API avec des extension functions.
Les extension functions ne sont pas des membres de classe — ce sont des fonctions normales qui nécessitent un import pour être utilisées dans un autre fichier. Kotlin propose deux options d'import : par nom de fonction ou avec renommage.
// Import by name
import com.example.extensions.isEmail
// Import with alias (to resolve conflicts)
import com.example.extensions.isEmail as isValidEmail
// Call after import
val valid = "test@test.com".isEmail()
Le renommage via as est utile pour les conflits de noms — par exemple, si deux bibliothèques fournissent une extension function avec le même nom pour le même type. Dans ce cas, vous pouvez importer l'une d'elles avec un nom différent et l'appeler en utilisant le nouveau nom.
Les extension functions peuvent être déclarées à différents niveaux :
| Niveau | Visibilité | Exemple |
|---|---|---|
| Top-level | Projet entier après import | fun String.isEmail() |
| Member extension | À l'intérieur de la classe propriétaire | class A { fun B.ext() } |
| Local | À l'intérieur d'une fonction | fun test() { fun String.ext() } |
Les member extension functions sont un cas particulier où une extension function est déclarée à l'intérieur d'une autre classe. Dans ce cas, à la fois le récepteur (this de la fonction) et les membres de la classe externe sont accessibles à l'intérieur de l'extension function.
Si une classe a une méthode avec la même signature qu'une extension function, le membre de classe est toujours appelé. Une extension function ne remplace jamais une méthode de classe — c'est une décision architecturale pour éviter les remplacements accidentels.
class User {
fun greet() = "Hello from class"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // "Hello from class"
}
Même si l'extension function est définie plus tard et a la même signature, le compilateur choisira la méthode de classe. Le compilateur Kotlin émet un avertissement lorsqu'il détecte cette situation. La seule façon d'appeler l'extension function lorsqu'une méthode de classe existe est de l'invoquer comme une fonction normale : greet(user).
Dans le développement Android, les extension functions sont devenues un outil standard pour travailler avec View, Context et les fragments. La bibliothèque Android KTX est construite sur des extension functions, fournissant des wrappers pratiques sur l'API Android.
// Extension function for working with View
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Extension function for Context — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// Extension function as DSL builder
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
L'extension function toast() rend les appels dépendants de Context concis : au lieu d'écrire Toast.makeText(context, message, length).show(), il suffit d'écrire context.toast("Texte"). Cela réduit le boilerplate et rend le code plus lisible.
Foire aux questions
Non, les extension functions utilisent le dispatch statique. Si vous déclarez une extension function pour une classe de base et la même pour une sous-classe, laquelle sera appelée est déterminée par le type statique de la variable à la compilation, pas par le type réel à l'exécution.
Vous pouvez déclarer des extension functions pour des types récepteurs nullables : fun String?.isNullOrEmail(). À l'intérieur d'une telle fonction, this peut être null, vous devez donc utiliser des opérateurs d'appel sécurisé ou des vérifications explicites de null.
Non, les extension functions sont compilées en méthodes statiques. Au niveau du bytecode, appeler une extension function est identique à appeler une méthode statique avec le récepteur comme premier paramètre. Aucune réflexion ni dispatch dynamique n'est impliqué.
Oui, les extension properties fonctionnent de manière similaire aux extension functions mais ne peuvent pas stocker d'état — seulement un getter et un setter. Par exemple : val List
En Java on écrit StringUtils.isEmail(str), alors qu'en Kotlin on écrit str.isEmail(). La différence n'est pas seulement syntaxique : les extension functions supportent l'autocomplétion dans l'IDE, améliorent la lisibilité des chaînes d'appels et permettent à l'IDE de suggérer des fonctions pertinentes pour un type spécifique. Java ne dispose pas de ces capacités.
Résumé
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.
Lisez aussi