How do I write custom getters and setters in Kotlin properties?

In Kotlin, properties can have custom getters and setters by defining get() and/or set(value) directly under the property.

var propertyName: Type = initialValue
    get() {
        return field
    }
    set(value) {
        field = value
    }

field is the backing field automatically generated by Kotlin when needed.

Custom getter

class Person(
    val firstName: String,
    val lastName: String
) {
    val fullName: String
        get() = "$firstName $lastName"
}

Usage:

val person = Person("Ada", "Lovelace")
println(person.fullName) // Ada Lovelace

Here, fullName does not store a value. It is computed every time it is accessed.

Custom setter

class User {
    var age: Int = 0
        set(value) {
            field = if (value >= 0) value else 0
        }
}

Usage:

val user = User()
user.age = -5
println(user.age) // 0

The setter validates the assigned value before storing it.

Custom getter and setter together

class Temperature {
    var celsius: Double = 0.0
        get() = field
        set(value) {
            field = value.coerceAtLeast(-273.15)
        }

    var fahrenheit: Double
        get() = celsius * 9 / 5 + 32
        set(value) {
            celsius = (value - 32) * 5 / 9
        }
}

Usage:

val temperature = Temperature()

temperature.celsius = 100.0
println(temperature.fahrenheit) // 212.0

temperature.fahrenheit = 32.0
println(temperature.celsius) // 0.0

Important rules

  • val properties can only have a custom getter, not a setter.
  • var properties can have both a getter and a setter.
  • Use field inside accessors when you want to refer to the property’s backing field.
  • Do not write propertyName = value inside its own setter, because that recursively calls the setter.

For example, avoid this:

var name: String = ""
    set(value) {
        name = value // recursive setter call
    }

Use this instead:

var name: String = ""
    set(value) {
        field = value
    }

Example with validation

class Product {
    var price: Double = 0.0
        set(value) {
            require(value >= 0) { "Price cannot be negative" }
            field = value
        }
}
val product = Product()
product.price = 19.99
println(product.price)

// product.price = -1.0
// Throws IllegalArgumentException: Price cannot be negative

So the basic pattern is:

var myProperty: String = ""
    get() = field
    set(value) {
        field = value.trim()
    }