throw if operator in Kotlin

Viewed 22056

What would be a more elegant way to rewrite the below code in kotlin.

if (xList.isEmpty()) {
   throw SomeException("xList was empty")
}

Do we have a throwif operator or something?

5 Answers

I like to use the takeIf standard function to validate, with elvis operator addition, it gives this:

xList.takeIf { it.isNotEmpty() } ?: throw SomeException("xList was empty")
    

I have to add that in most cases an IllegalArgumentException is what I need, and it is simpler to just use require.
In cases that we need an IllegalStateException, we can rather use check.

See also: checkNotNull, requireNotNull, error

Yet another suggestion, terse and not requiring additional code :

xList.isNotEmpty() || throw SomeException("xList was empty")

It works because throw is an expression, having the type Nothing which is a subtype of everything, including Boolean.

In Kotlin library, there are functions which throw exception if the input is invalid, e.g. requireNotNull(T?, () -> Any). You can refer to these functions and write a similar function to handle empty list if you want.

public inline fun <T> requireNotEmpty(value: List<T>?, lazyMessage: () -> Any): List<T> {
    if (value == null || value.isEmpty()) {
        val message = lazyMessage()
        throw IllegalArgumentException(message.toString())
    } else {
        return value
    }
}

//Usage:
requireNotEmpty(xList) { "xList was empty" }

Or simply use require(Boolean, () -> Any):

require(!xList.isEmpty()) { "xList was empty" }

I don't know of a function in the standard library, but you can easily do this yourself:

/**
 * Generic function, evaluates [thr] and throws the exception returned by it only if [condition] is true
 */
inline fun throwIf(condition: Boolean, thr: () -> Throwable) {
    if(condition) {
        throw thr()
    }
}

/**
 * Throws [IllegalArgumentException] if this list is empty, otherwise returns this list.
 */
fun <T> List<T>.requireNotEmpty(message: String = "List was empty"): List<T> {
    throwIf(this.isEmpty()) { IllegalArgumentException(message) }
    return this
}

// Usage
fun main(args: Array<String>) {
    val list: List<Int> = TODO()
    list.filter { it > 3 }
        .requireNotEmpty()
        .forEach(::println)
}

The original code is compact, transparent and flexible. An extension fun with fixed exception may be more compact.

infix fun String.throwIf(b: Boolean) {
    if (b) throw SomeException(this)
}

"xList was empty" throwIf xList.isEmpty()
Related