extensiefunctie — Kotlin-mechanisme waarmee nieuwe methoden aan bestaande klassen kunnen worden toegevoegd zonder overerving en zonder wijziging van de broncode. De functie wordt gedeclareerd met een prefix in de vorm van een ontvangertype en wordt aangeroepen als een gewone methode van dit type. Volgens Kotlin Documentation, 2025 worden extensiefuncties gecompileerd naar statische methoden met de eerste parameter-ontvanger, wat nul overhead garandeert in runtime vergeleken met gewone aanroepen.
Belangrijkste
Een extensiefunctie is een functie die buiten de klasse wordt gedeclareerd, maar als zijn methode wordt aangeroepen. Het accepteert een ontvangertype waaraan een nieuwe methode wordt toegevoegd. Binnen de functie verwijst het sleutelwoord this naar het exemplaar van het ontvangertype. Deze aanpak maakt het mogelijk om final-klassen, klassen van externe bibliotheken en zelfs primitieve typen uit te breiden zonder wrappers te maken.
In tegenstelling tot Java, waar het toevoegen van een methode aan een bestaande klasse ofwel overerving ofwel een statische hulpklasse vereist, biedt Kotlin een elegante oplossing zonder boilerplate. Volgens gegevens van het Kotlin Foundation-onderzoek (2024) behoren extensiefuncties tot de vijf meest gebruikte taalfuncties — 78% van de Kotlin-ontwikkelaars gebruikt ze in het dagelijks werk.
De Kotlin-compiler vertaalt de extensiefunctie naar een statische methode, waarbij het ontvangerexemplaar als eerste argument wordt doorgegeven. Dit betekent dat extensiefuncties de bytecode van de doelklasse niet wijzigen en inkapseling niet schenden — alleen openbare velden en methoden van de ontvanger zijn toegankelijk.
Gebruik extensiefuncties om schone hulpfuncties te schrijven die logisch gebonden zijn aan een specifiek type, maar niet aan de broncode kunnen worden toegevoegd.
De basissyntax van een extensiefunctie: naam van het ontvangertype, punt, functienaam, dan parameters en retourtype. Binnen de functie is de ontvanger toegankelijk via this.
// Extensiefunctie voor String
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
// Aangeroepen als gewone String-methode
val result = "user@example.com".isEmail() // true
In dit voorbeeld wordt isEmail() beschikbaar voor alle strings. Binnen de functie is this de string zelf waarop de methode wordt aangeroepen. Kotlin staat toe this in de meeste gevallen weg te laten — je kunt gewoon contains("@") schrijven in plaats van this.contains("@").
Extensiefuncties kunnen extra parameters accepteren en waarden van elk type retourneren. Dit maakt ze volwaardige functies, niet alleen syntaxissuiker.
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)
De parameter default bepaalt de waarde die voor een lege lijst wordt geretourneerd. Een extensiefunctie kan generic zijn — het type List
Extensiefuncties in Kotlin gebruiken statische dispatch, niet virtuele. Dit is het belangrijkste verschil met gewone klassenmethoden. Welke extensiefunctie wordt aangeroepen, wordt in de compilatiefase bepaald op basis van het statische type van de variabele, niet op basis van het werkelijke type in runtime.
open class Animal
class Dog : Animal()
fun Animal.speak() = "Diergeluid"
fun Dog.speak() = "Blaf"
fun test() {
val animal: Animal = Dog()
println(animal.speak()) // „Diergeluid” — statisch type Animal
val dog: Dog = Dog()
println(dog.speak()) // „Blaf” — statisch type Dog
}
Hoewel de variabele animal naar een Dog-exemplaar verwijst, wordt de extensiefunctie voor Animal aangeroepen, omdat het statische type van de variabele Animal is. Als speak() een virtuele klassemethode was, zou Dog.speak() zijn aangeroepen. Deze eigenschap is belangrijk om in overweging te nemen bij het ontwerpen van API's op basis van extensiefuncties.
Extensiefuncties zijn geen klassenleden — het zijn gewone functies die import vereisen voor gebruik in een ander bestand. Kotlin biedt twee importvarianten: op functienaam of met hernoeming.
// Import op naam
import com.example.extensions.isEmail
// Import met alias (om conflicten op te lossen)
import com.example.extensions.isEmail as isValidEmail
// Aanroep na import
val valid = "test@test.com".isEmail()
Hernoeming via as is nuttig bij naamconflicten — bijvoorbeeld als twee bibliotheken een extensiefunctie met dezelfde naam voor hetzelfde type bieden. In dit geval kan men een ervan onder een andere naam importeren en via de nieuwe naam aanroepen.
Extensiefuncties kunnen op verschillende niveaus worden gedeclareerd:
| Niveau | Zichtbaarheid | Voorbeeld |
|---|---|---|
| Top-level | Hele project na import | fun String.isEmail() |
| Member extension | Binnen de eigenaarklasse | class A { fun B.ext() } |
| Local | Binnen de functie | fun test() { fun String.ext() } |
Member extension functions — een speciaal geval waarbij de extensiefunctie binnen een andere klasse wordt gedeclareerd. In dit geval zijn binnen de extensiefunctie zowel de ontvanger (this van de functie) als de leden van de externe klasse toegankelijk.
Als de klasse een methode heeft met dezelfde handtekening als de extensiefunctie, wordt altijd het klassenlid aangeroepen. Een extensiefunctie overschrijft nooit de klassemethode — dit is een architectonische beslissing om accidentele overschrijvingen te voorkomen.
class User {
fun greet() = "Hallo vanuit klasse"
}
fun User.greet() = "Hello from extension"
fun main() {
val user = User()
println(user.greet()) // „Hallo vanuit klasse”
}
Zelfs als de extensiefunctie later wordt gedefinieerd en dezelfde handtekening heeft, kiest de compiler de klassemethode. De Kotlin-compiler geeft een waarschuwing bij het detecteren van een dergelijke situatie. De enige manier om een extensiefunctie aan te roepen in aanwezigheid van een klassemethode is door deze als een gewone functie aan te spreken: greet(user).
In Android-ontwikkeling zijn extensiefuncties een standaardinstrument geworden voor het werken met View, Context en fragmenten. De Android KTX-bibliotheek is gebouwd op extensiefuncties en biedt handige wrappers voor de Android API.
// Extensiefunctie voor werken met View
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.GONE
}
// Extensiefunctie voor Context — toast
fun Context.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
// Extensiefunctie als DSL-bouwer
fun String.colorFormat(color: String): String =
"$color$this\u001b[0m"
De extensiefunctie toast() maakt Context-afhankelijke aanroepen beknopt: in plaats van Toast.makeText(context, message, length).show() te schrijven, volstaat context.toast("Tekst"). Dit vermindert boilerplate en maakt de code leesbaarder.
Veelgestelde vragen
Nee, extensiefuncties gebruiken statische dispatch. Als u een extensiefunctie voor de basisklasse en dezelfde voor de subklasse declareert, welke wordt aangeroepen, wordt bepaald door het statische type van de variabele in de compilatiefase, niet door het werkelijke type in runtime.
U kunt extensiefuncties declareren voor nullable ontvangertypen: fun String?.isNullOrEmail(). Binnen zo'n functie kan this null zijn, daarom moet u veilige aanroepoperators of expliciete null-controle gebruiken.
Nee, extensiefuncties worden gecompileerd naar statische methoden. Op bytecode-niveau is de aanroep van een extensiefunctie identiek aan de aanroep van een statische methode met de eerste parameter-ontvanger. Geen reflectie of dynamische dispatch.
Ja, extensie-eigenschappen werken vergelijkbaar met extensiefuncties, maar kunnen geen status opslaan — alleen getter en setter. Bijvoorbeeld: val List<Int>.sum get() = reduce(Int::plus). Ze worden ook gecompileerd naar statische getter/setter-methoden.
In Java schrijft u StringUtils.isEmail(str), in Kotlin — str.isEmail(). Het verschil zit niet alleen in de syntax: extensiefuncties ondersteunen automatisch aanvullen in de IDE, verbeteren de leesbaarheid van aanroepketens en stellen de IDE in staat relevante functies voor een specifiek type voor te stellen. In Java bestaan dergelijke mogelijkheden niet.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook