Skip to content

Instantly share code, notes, and snippets.

@ajay-dewari
Last active February 7, 2025 05:26
Show Gist options
  • Save ajay-dewari/314b010ac69c8f0189153c44d63a0c1d to your computer and use it in GitHub Desktop.
Save ajay-dewari/314b010ac69c8f0189153c44d63a0c1d to your computer and use it in GitHub Desktop.
Throwing exceptions in Kotlin

Throwing exceptions in Kotlin Using the require, check, and error functions

In programming, it's common to write an if statement to check a precondition, for example:

fun doSomething(value: Int) {
    if (value < 0) {
        throw IllegalArgumentException("value cannot be negative")
    }
    
    // do something
}

Kotlin offers some helper functions to make your code more concise.

The require function We can rewrite the code above in the following way:

fun doSomething(value: Int) {
    require(value > 0) { "value cannot be negative" }

    // do something
}

The require function helps validate function arguments. If the condition isfalse, it will throw an IllegalArgumentException with the message provided in the lambda.

The requireNotNull function This function has a self-explanatory name. It will check if the value is null; if it's false, it will throw an IllegalArgumentException with the message provided in the lambda. See the example:

fun plusOne(number: Int?) : Int {
    requireNotNull(number) { "number cannot be null" }
    return number + 1
}

The smart cast works in this scenario. This is why we can sum the number in the second line without worrying about null values.

The check function The check function has the same signature as the require function, but it will throw an IllegalStateException instead. This function is not used to validate parameters. You should use it to validate the internal state of a class. See this example:

class Queue {
    private val queue = ArrayDeque<String>(10)

    fun enqueue(id: String) {
        check(queue.size == 10) { "Queue is full" }
        queue.push(id)
    }
    
    fun dequeue(): String {
        check(queue.isEmpty()) { "Queue is empty" }
        return queue.pop()
    }
}

If any of the validations fail, an IllegalStateException will be thrown.

The checkNotNull function This works the same way as the requireNotNull function, but it throws an IllegalStateException instead of an IllegalArgumentException. This function is to be used to validate null inside the state of a class, just like the check function. Example:

data class User(
    val id: String,
    val name: String,
    val email: String,
)
interface UserRepository {
    fun findById(): User?
}

interface EmailService {
    fun sendEmail(email: String, message: String)
}

class SendEmailUseCase(
    private val userRepository: UserRepository,
    private val emailService: EmailService,
) {
    fun sendMessage(message: String) {
        val user = userRepository.findById()
        checkNotNull(user) { "User not found" }

        emailService.sendEmail(user.email, message)
    }
}
The error function
The error function always throws an IllegalStateException when it's called. This is an example of the error function in action. It's common to see it used together with the Elvis operator.

class SendEmailUseCase(
    private val userRepository: UserRepository,
    private val emailService: EmailService,
) {
    fun sendMessage(message: String) {
        val user = userRepository.findById()
            ?: error("User not found")

        emailService.sendEmail(user.email, message)
    }
}
Another common usage is in the when expression:

fun processMessage(message: Message): String {
    return when (message.type) {
        "info" -> "INFO: ${message.message}"
        "warning" -> "WARNING: ${message.message}"
        "error" -> "ERROR: ${message.message}"
        else -> error("Unknown message type ${message.type}")
    }
}

Conclusion As we can see, Kotlin offers some functions to validate preconditions that can make your code less verbose and more idiomatic. The functions require and check have the same signature but throw different exceptions and have different purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment