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.15Custom 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") // worksLazy 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]