🎓 A1Learner
🔍
0 of 37 lessons completed

Kotlin Require and Check

require and check test a condition and throw an exception when the condition fails. require guards values passed in and check guards the state of an object.

require guards an argument

discount calls require on the percent argument. The failing call lands in the catch block and prints the lazy message.

fun discount(price: Int, percent: Int): Int {
    require(percent in 0..100) { "Percent must be between 0 and 100" }
    return price - price * percent / 100
}

fun main() {
    println(discount(200, 25))
    try {
        println(discount(200, 140))
    } catch (e: IllegalArgumentException) {
        println(e.message)
    }
}

requireNotNull on a nullable argument

requireNotNull hands back the stored name when it is not null. A null name throws IllegalArgumentException with the given message.

fun greet(name: String?): String {
    val checked = requireNotNull(name) { "Name is required" }
    return "Hello, $checked"
}

fun main() {
    println(greet("Ana"))
    try {
        println(greet(null))
    } catch (e: IllegalArgumentException) {
        println(e.message)
    }
}

check guards object state

walkThrough calls check on the open state of the door. The first call fails the test and the later calls pass it.

class Door {
    private var open = false

    fun openDoor() {
        open = true
        println("Opened")
    }

    fun walkThrough() {
        check(open) { "Door is closed" }
        println("Walked through")
    }
}

fun main() {
    val door = Door()
    try {
        door.walkThrough()
    } catch (e: IllegalStateException) {
        println(e.message)
    }
    door.openDoor()
    door.walkThrough()
}

error throws at once

The else branch of the when calls error with a message. That call throws IllegalStateException and the catch block prints its message.

fun roleName(code: Int): String {
    return when (code) {
        1 -> "Admin"
        2 -> "Guest"
        else -> error("Unknown code")
    }
}

fun main() {
    println(roleName(1))
    try {
        println(roleName(9))
    } catch (e: IllegalStateException) {
        println(e.message)
    }
}

Example

class Ticket(val seats: Int) {
    private var sold = 0

    fun buy(count: Int) {
        require(count > 0) { "Count must be positive" }
        check(sold + count <= seats) { "Not enough seats" }
        sold += count
        println(sold)
    }
}

fun main() {
    val ticket = Ticket(3)
    ticket.buy(2)
    try {
        ticket.buy(0)
    } catch (e: IllegalArgumentException) {
        println(e.message)
    }
    try {
        ticket.buy(2)
    } catch (e: IllegalStateException) {
        println(e.message)
    }
}

Key points

  • require throws IllegalArgumentException when its condition is false.
  • The block after a require call builds the message only when the test fails.
  • requireNotNull returns the value when it is not null and throws when it is null.
  • check throws IllegalStateException when its condition is false.
  • error throws IllegalStateException with a given message at once.
  • A catch block can read the message of each failure with e.message.

In this example, Ticket sells seats with two guards. require rejects a count of zero as a bad argument. check rejects a sale that passes the seat total as a bad state. The first sale passes both guards and prints 2.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Kotlin Playground

Exercise

Which exception type does a failing require call throw?