ZetCode

Kotlin Extension Functions

last modified March 22, 2025

Kotlin extension functions let you bolt new tricks onto existing classes without touching their blueprints—perfect for jazzing up libraries or third-party code you can't tweak. This tutorial unpacks extension functions with vivid, real-world examples that bring their power to life.

Basic Extension Function

An extension function slips into a class by prefixing its name with the target type. Here's a simple twist that adds a welcome function to String, giving it a friendly voice.

BasicExtension.kt
fun String.welcome(): String {
    return "Welcome, $this, to the team!"
}

fun main() {
    val user = "Alice"
    println(user.welcome())
}

welcome spices up String with a greeting, using this to reference the string. Imagine this in an HR app, greeting new hires with flair—no class edits needed.

Extension Function with Parameters

Extension functions can grab parameters to flex their muscles. This one adds a shout function to String, letting you amplify text on demand.

ExtensionWithParams.kt
fun String.shout(times: Int): String {
    return this.uppercase() + "!".repeat(times)
}

fun main() {
    val alert = "warning"
    println(alert.shout(3))
}

shout takes a times parameter, boosting the string with exclamations. Picture this in a notification system, turning "warning" into a loud alert—customizable and snappy.

Extension Function for Collections

Collections like List can gain new powers too. This example crafts a rotate function to shuffle list items, keeping things fresh.

CollectionExtension.kt
fun <T> List<T>.rotate(shift: Int): List<T> {
    val size = this.size
    if (size == 0) return this
    val normalizedShift = (shift % size + size) % size
    return this.drop(normalizedShift) + this.take(normalizedShift)
}

fun main() {
    val tasks = listOf("Code", "Test", "Deploy")
    println(tasks.rotate(1))
}

rotate shifts list elements, handling edge cases with modulo. Think of a task scheduler cycling priorities—rotating "Code" to the back keeps your workflow humming without altering the original List.

Extension Function for Nullable Types

Nullable types get love too, with extensions that handle null gracefully. This adds a safeTrim function to String?, tidying up without tripping over nothing.

NullableExtension.kt
fun String?.safeTrim(): String {
    return this?.trim() ?: ""
}

fun main() {
    val input: String? = null
    println(input.safeTrim())
}

safeTrim trims a nullable string, defaulting to empty if null. Perfect for a form processor cleaning user input—null or not, it's handled smoothly with Kotlin's Elvis operator.

Extension Function for Custom Classes

Custom classes can sprout new abilities too. Here, a Person class gains a needsID check to flag minors needing extra checks.

CustomClassExtension.kt
class Person(val name: String, val age: Int)

fun Person.needsID(): Boolean {
    return this.age < 21
}

fun main() {
    val guest = Person("Bob", 19)
    println(guest.needsID())
}

needsID tags Person with a minor check. Imagine this at a venue gate, flagging guests under 21 for ID verification—cleanly bolted onto the class without rewriting it.

Extension Function for Companion Objects

Companion objects can level up with extensions, enhancing static-like behavior. This adds a fromEmail factory to User's companion.

CompanionObjectExtension.kt
class User(val username: String) {
    companion object
}

fun User.Companion.fromEmail(email: String): User {
    return User(email.substringBefore("@"))
}

fun main() {
    val user = User.fromEmail("alice@site.com")
    println(user.username)
}

fromEmail crafts a User from an email, snipping the username. Think signup flows—extracting a handle from an email without cluttering the User class itself.

Extension Function for Generic Types

Generic types bend to extensions too, offering reusable tricks across types. This adds a summarize function to List for quick stats.

GenericExtension.kt
fun <T> List<T>.summarize(): String {
    return "Count: ${this.size}, Items: ${this.joinToString()}"
}

fun main() {
    val scores = listOf(85, 92, 78)
    println(scores.summarize())
}

summarize tallies and lists any List. Picture a quiz app spitting out a score recap—generic, concise, and ready for any data type.

Extension with Lambda

Extensions can wield lambdas for dynamic behavior, letting callers shape the action. This adds a transform function to String.

LambdaExtension.kt
fun String.transform(action: (String) -> String): String {
    return action(this)
}

fun main() {
    val text = "hello"
    println(text.transform { it.capitalize() })
}

transform hands off the string to a lambda, here capitalizing it. Think text editors—users pick the tweak (capitalize, reverse), and the extension delivers, all without touching String.

Chaining Extensions

Extensions can chain, stacking effects for sleek workflows. This pairs mask and shorten on String.

ChainingExtension.kt
fun String.mask(): String = this.replaceRange(1, length - 1, "*".repeat(length - 2))
fun String.shorten(max: Int): String = if (length <= max) this else substring(0, max) + "..."

fun main() {
    val email = "alice@site.com"
    println(email.mask().shorten(10))
}

mask hides middle chars, then shorten caps length. Ideal for a privacy filter—obscuring emails in logs, then trimming for display, all in a fluid chain.

Extension with Receiver Scope

Extensions can tap the receiver's scope for richer logic. This adds logSelf to Any, logging with type info.

ReceiverScopeExtension.kt
fun Any.logSelf(): String {
    return "Log: ${this::class.simpleName} = $this"
}

fun main() {
    val num = 42
    println(num.logSelf())
}

logSelf uses this and its class name for a log entry. Great for debugging—any object can report itself with type context, no subclassing required.

Best Practices for Using Extension Functions

Source

Kotlin Extension Functions Documentation

This tutorial cracked open Kotlin extension functions, revealing their knack for sprucing up classes with fresh moves. Through practical examples, we've seen how they boost modularity and reuse, from strings to custom types, with Kotlin's signature elegance.

Author

My name is Jan Bodnar, and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all Kotlin tutorials.