How to catch many exceptions at the same time in Kotlin?

KotlinException

Kotlin Problem Overview


try { 

} catch (ex: MyException1, MyException2 ) {
    logger.warn("", ex)
}

or

try { 

} catch (ex: MyException1 | MyException2 ) {
    logger.warn("", ex)
}

As a result, a compilation error: Unresolved reference: MyException2.

How can I catch many exceptions at the same time on Kotlin?

Kotlin Solutions


Solution 1 - Kotlin

Update: Vote for the following issue KT-7128 if you want this feature to land in Kotlin. Thanks @Cristan

According to this thread this feature is not supported at this moment.

> abreslav - JetBrains Team

> Not at the moment, but it is on the table

You can mimic the multi-catch though:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}

Solution 2 - Kotlin

To add to miensol's answer: although multi-catch in Kotlin isn't yet supported, there are more alternatives that should be mentioned.

Aside from the try-catch-when, you could also implement a method to mimic a multi-catch. Here's one option:

fun (() -> Unit).catch(vararg exceptions: KClass<out Throwable>, catchBlock: (Throwable) -> Unit) {
    try { 
        this() 
    } catch (e: Throwable) {
        if (e::class in exceptions) catchBlock(e) else throw e
    }
}

And using it would look like:

fun main(args: Array<String>) {
    // ...
    {
        println("Hello") // some code that could throw an exception

    }.catch(IOException::class, IllegalAccessException::class) {
        // Handle the exception
    }
}

You'll want to use a function to produce a lambda rather than using a raw lambda as shown above (otherwise you'll run into "MANY_LAMBDA_EXPRESSION_ARGUMENTS" and other issues pretty quickly). Something like fun attempt(block: () -> Unit) = block would work.

Of course, you may want to chain objects instead of lambdas for composing your logic more elegantly or to behave differently than a plain old try-catch.

I would only recommend using this approach over miensol's if you are adding some specialization. For simple multi-catch uses, a when expression is the simplest solution.

Solution 3 - Kotlin

The example from aro is very good but if there are inheritances, it won't work like in Java.

Your answer inspired me to write an extension function for that. To also allow inherited classes you have to check for instance instead of comparing directly.

inline fun multiCatch(runThis: () -> Unit, catchBlock: (Throwable) -> Unit, vararg exceptions: KClass<out Throwable>) {
try {
    runThis()
} catch (exception: Exception) {
    val contains = exceptions.find {
        it.isInstance(exception)
    }
    if (contains != null) catchBlock(exception)
    else throw exception
}}

To see how to use, you can have a look in my library on GitHub here

Solution 4 - Kotlin

This way you can take multiple Catch and with the MultiCatch method you can detect Exceptions

import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf

class NegetiveNumber : Exception()
class StringFalse : Exception()

fun <R> Exception.multiCatch(vararg classes: KClass<*>, block: () -> R): R {
    return if (classes.any {
            this::class.isSubclassOf(it)
        }) block()
    else throw this
}
class Human() {
    var name = ""
        set(name) {
            if (name.isEmpty()) {
                throw StringFalse()
            } else {
                field = name
            }
        }
    var age = 0
        set(age) {
            if (age <= 0) {
                throw NegetiveNumber()
            } else {
                field = age
            }
        }
}
fun main() {
    val human = Human()
    human.name = "Omidreza"
    human.age = 0

    try {
        println(human.name)
        println(human.age)
    } catch (e: Exception) {
  

      e.multiCatch(NegetiveNumber::class, StringFalse::class) {
            println(e.message)
        }
    }finally {
        println("end")
    }
}

this is multiCatch():

fun <R> Exception.multiCatch(vararg classes: KClass<*>, block: () -> R): R {
        return if (classes.any {
                this::class.isSubclassOf(it)
            }) block()
        else throw this
}

Solution 5 - Kotlin

In Kotlin you can do this:

try{
} catch(e: MyException1){
} catch(e: MyException2){
} catch(e: MyException3){
} [...]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnt20View Question on Stackoverflow
Solution 1 - KotlinmiensolView Answer on Stackoverflow
Solution 2 - KotlinAroView Answer on Stackoverflow
Solution 3 - KotlinMark KowalskiView Answer on Stackoverflow
Solution 4 - KotlinOmidreza BagherianView Answer on Stackoverflow
Solution 5 - KotlinRFMView Answer on Stackoverflow