Search code examples
kotlingetter-setter

Why am I am not getting a runtime exception with message "no empty, please" when running following code


Why am I am not getting a runtime exception with message "no empty, please" when running following code: code:

class Car(val name: String, col: String) {
    val fuel = 100
    var color = col
        set(value) {
            if (value.isBlank()) {
                throw RuntimeException("no empty, please")
            }
            field = value
        }
}
fun main() {
    var car = Car("Maruti", "")
    println("Your car ${car.name} is of ${car.color}")
}

Solution

  • When an object gets initialized, the setter is not used. In your class, the value of the property color would be directly initialized using the col parameter from the constructor.

    class Car(val name: String, col: String) {
        val fuel = 100
        // color is getting its initial value from the 
        // constructor directly. Setter won't be used here
        var color = col
            set(value) {
                if (value.isBlank()) {
                    throw RuntimeException("no empty, please")
                }
                field = value
            }
    }
    

    In your main function, you are not calling the setter.

    fun main() {
        // here only arguments are being passed to the constructor
        var car = Car("Maruti", "")
        println("Your car ${car.name} is of ${car.color}")
    }
    

    However, if you try to use the setter with an empty string the exception would be thrown.

    fun main() {
            // here only arguments are being passed to the constructor
            var car = Car("Maruti", "")
    
            // this line would call the setter and 
            // exception would be thrown 
            car.color = ""
    
            println("Your car ${car.name} is of ${car.color}")
    }
    

    If you want to validate parameters during the object's initialization then you can use init blocks to put your logic. The codes in init blocks are executed when the object is initialized for the first time. Arguments passed in the constructor and previously initialized properties (in the constructor as well as before the init block in terms of line numbers) are in the scope of the init blocks.

    class Car(val name: String, col: String) {
    
        init {
            if (col.isBlank()) throw RuntimeException("no empty, please")
        }
    
        val fuel = 100
    
        var color = col
            set(value) {
                if (value.isBlank()) {
                    throw RuntimeException("no empty, please")
                }
                field = value
            }
    }
    

    Because of the validation in the init block, it would throw RuntimeException if you try to initialize it with an empty string.

    A more idiomatic way to do this kind of validation is using require function from the Kotlin standard library.

    init {
            require(col.isNotBlank()) {"no empty, please"}
    }
    

    require would throw IllegalArgumentException if the check turns out to be false with the given message.