Kotlin Tutoial

Basics

Control Flow

Array & String

Functions

Collections

OOPs Concept

Exception Handling

Null Safety

Regex & Ranges

Java Interoperability

Miscellaneous

Android

Kotlin Setters and Getters

In Kotlin, properties are a first-class feature, which means you can have fields with getters and setters without having to define methods as in some other languages. The Kotlin compiler generates a default getter and setter for mutable properties, and a getter for read-only properties. However, you can also customize them if needed.

Basics:

  • A getter is a method that gets the value of a property.
  • A setter is a method that sets the value of a property.

Default Getters and Setters:

For every property in Kotlin, the compiler generates a default getter and setter (for var properties):

class Person {
    var name: String = "Alice"
    val age: Int = 25
}

val p = Person()
println(p.name) // Uses the default getter
p.name = "Bob"  // Uses the default setter

Custom Getters:

You can define a custom getter for a property. The custom getter will be called every time you access the property:

class Rectangle {
    var length: Int = 0
    var breadth: Int = 0
    val area: Int
        get() = length * breadth  // Custom getter for area
}

val r = Rectangle()
r.length = 5
r.breadth = 10
println(r.area) // Outputs 50

Custom Setters:

You can also define a custom setter. The setter is always marked with the set keyword:

class Person {
    var age: Int = 0
        set(value) {
            if (value > 0) {
                field = value // 'field' refers to the backing field
            } else {
                println("Age can't be negative!")
            }
        }
}

val p = Person()
p.age = -5  // Outputs: Age can't be negative!

In the custom setter, value is an implicit parameter that represents the value you're trying to set. The keyword field is a special identifier that references the backing field of the property.

Backing Fields:

Sometimes, you might want to store the values of properties in fields. Kotlin provides a backing field mechanism for this. When you need to access the stored value of a property in a getter or setter, you can use the field identifier, which refers to this backing field:

var counter = 0
    set(value) {
        if (value >= 0) {
            field = value
        }
    }

Backing Properties:

In some cases, you might need more control over your property, for which you can use a backing property:

private var _table: Map<String, Int>? = null
val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap()  // Initialize it lazily
        }
        return _table ?: throw AssertionError("Set to null by another thread")
    }

Conclusion:

Kotlin provides a concise way to handle getters and setters through properties. With custom getters and setters, you can add logic to property access without having to define separate methods. This results in cleaner, more readable code.

  1. Declaring properties with getters and setters in Kotlin:

    • Use the var keyword for mutable properties with default getters and setters.
    var myProperty: String = "Hello"
    
  2. Customizing getters and setters in Kotlin:

    • Customize the behavior of getters and setters.
    var customProperty: Int = 0
        get() = field * 2
        set(value) {
            field = value + 1
        }
    
  3. Read-only properties in Kotlin:

    • Use the val keyword for read-only properties with a default getter.
    val readOnlyProperty: Double = 3.14
    
  4. Backing fields in Kotlin properties:

    • Access the automatically generated backing field using the field keyword.
    var counter: Int = 0
        set(value) {
            field = if (value >= 0) value else 0
        }
    
  5. Visibility modifiers in Kotlin properties:

    • Control the visibility of properties with modifiers like private, protected, or internal.
    internal var internalProperty: String = "Internal"
    
  6. Using lateinit for late-initialized properties in Kotlin:

    • Mark properties with lateinit when their values will be assigned later.
    lateinit var lateProperty: String
    
  7. Observable properties in Kotlin:

    • Utilize the ObservableProperty delegate for properties that need observation.
    var observableProperty by Delegates.observable("Initial") { _, old, new ->
        println("$old -> $new")
    }
    
  8. Delegated properties in Kotlin:

    • Leverage delegation for custom behavior in properties.
    var delegatedProperty: String by CustomDelegate()
    
  9. Overriding getters and setters in Kotlin:

    • Override the default getters and setters in subclasses.
    open class BaseClass {
        open var property: String = "Base"
    }
    
    class DerivedClass : BaseClass() {
        override var property: String
            get() = super.property.toUpperCase()
            set(value) {
                super.property = value.toLowerCase()
            }
    }
    
  10. Properties and data classes in Kotlin:

    • Data classes automatically generate component functions for properties.
    data class Person(val name: String, val age: Int)
    val person = Person("Alice", 30)
    val (name, age) = person
    
  11. Properties vs fields in Kotlin:

    • Properties encapsulate fields and provide getters and setters.
    class MyClass {
        var property: Int = 0 // Property with getter and setter
        val readOnlyProperty: Int = 42 // Property with only getter
    }
    
  12. Accessing properties in Java from Kotlin:

    • Kotlin properties seamlessly integrate with Java code.
    MyClass myClass = new MyClass();
    int value = myClass.getProperty();
    myClass.setProperty(10);