Kotlin Properties

Properties are the data fields of a class. In Kotlin, properties are more powerful than simple variables — they come with built-in getters and setters, support for computed values, and lazy initialization.

Basic Properties

class Person {
    var name: String = ""
    var age: Int = 0
    val id: Int = (1000..9999).random()  // set once, read-only
}

val p = Person()
p.name = "Maria"
p.age = 28
println("${p.name}, age ${p.age}, ID: ${p.id}")

Custom Getter

A getter computes a value each time the property is read:

class Temperature(val celsius: Double) {
    val fahrenheit: Double
        get() = celsius * 9 / 5 + 32

    val kelvin: Double
        get() = celsius + 273.15
}

val temp = Temperature(100.0)
println("Celsius   : ${temp.celsius}")     // 100.0
println("Fahrenheit: ${temp.fahrenheit}")  // 212.0
println("Kelvin    : ${temp.kelvin}")      // 373.15

Custom Setter

A setter runs logic when a property is assigned a new value:

class Counter {
    var count: Int = 0
        set(value) {
            field = if (value < 0) 0 else value   // prevent negative count
        }
}

val c = Counter()
c.count = 10
println(c.count)    // 10

c.count = -5
println(c.count)    // 0 (clamped to 0)

The field Keyword


Inside a setter, "field" refers to the actual stored value.
Without field, you'd cause infinite recursion:

  set(value) {
      count = value   ← calls setter again → infinite loop!
  }

  set(value) {
      field = value   ← directly sets the backing field → correct
  }

Computed Properties

class ShoppingCart(val items: List) {
    val subtotal: Double
        get() = items.sum()

    val tax: Double
        get() = subtotal * 0.12

    val total: Double
        get() = subtotal + tax

    val itemCount: Int
        get() = items.size
}

val cart = ShoppingCart(listOf(500.0, 1200.0, 300.0))
println("Items    : ${cart.itemCount}")   // 3
println("Subtotal : ₹${cart.subtotal}")   // ₹2000.0
println("Tax      : ₹${cart.tax}")        // ₹240.0
println("Total    : ₹${cart.total}")      // ₹2240.0

Late-Initialized Properties

Use lateinit var when you cannot assign a value in the constructor but will definitely set it before use:

class DatabaseConnection {
    lateinit var connectionString: String

    fun connect(host: String, db: String) {
        connectionString = "jdbc:postgresql://$host/$db"
        println("Connected: $connectionString")
    }

    fun query(sql: String) {
        if (!::connectionString.isInitialized) {
            println("Not connected!")
            return
        }
        println("Running: $sql on $connectionString")
    }
}

val db = DatabaseConnection()
db.query("SELECT *")       // Not connected!
db.connect("localhost", "mydb")
db.query("SELECT * FROM users")  // works

Lazy Properties

A lazy property computes its value only on the first access and caches the result:

class HeavyReport {
    val data: List by lazy {
        println("Loading data...")   // runs only on first access
        listOf("Row 1", "Row 2", "Row 3")
    }
}

val report = HeavyReport()
println("Report created")
println(report.data)   // "Loading data..." then the list
println(report.data)   // just the list — no reload

Output:

Report created
Loading data...
[Row 1, Row 2, Row 3]
[Row 1, Row 2, Row 3]

Leave a Comment

Your email address will not be published. Required fields are marked *