163
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?

Jonik
  • 80,077
  • 70
  • 264
  • 372
Ant20
  • 1,993
  • 2
  • 12
  • 16

5 Answers5

195

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
    }
}
miensol
  • 39,733
  • 7
  • 116
  • 112
  • 2
    I'm copying `pdvrieze` reply here: `This certainly works, but is slightly less efficient as the caught exception is explicit to the jvm (so a non-processed exception will not be caught and rethrown which would be the corollary of your solution) ` – solidak Jul 25 '17 at 11:47
  • this is just not the same. it will catch all exceptions, while you only want to catch certain types of exceptions with multi-catch. – IARI Oct 26 '17 at 07:24
  • 4
    @IARI The `else` clause rethrows the _unwanted_ exception. – miensol Oct 26 '17 at 08:10
  • true, i overlooked that - but its not beautiful, as I suppose it messes with the structure of the stacktrace – IARI Oct 26 '17 at 08:58
  • 3
    @IARI [The original stacktrace is preserved](https://stackoverflow.com/questions/1097527/rethrowing-exceptions-in-java-without-losing-the-stack-trace) – miensol Oct 26 '17 at 11:21
  • 6
    Even if you throw away the arguments of elegance and ugliness aside, Kotlin (which claims to be concise) is actually 2x as verbose as Java in this case – Phileo99 Dec 22 '17 at 19:53
  • 3
    That gets flagged by Detekt because you're catching too generic an exception ;-) – kenyee Aug 21 '18 at 15:03
  • 1
    Go to https://youtrack.jetbrains.com/issue/KT-7128 to track this issue. – Cristan Feb 12 '19 at 14:43
14

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.

Aro
  • 609
  • 9
  • 15
  • If I understand it correctly you pass classes in your catch, but param `exceptions` takes objects. – nllsdfx Jun 18 '18 at 11:45
  • you're awesome man @aro, thanks for providing this alternative – mochadwi Jan 10 '20 at 07:30
  • This alternative is good, thanks Aro :) Better than nothing. However, I hope they will get to that feature although my issue KT-7128 was opened 5 years ago :-) – zdenda.online Apr 26 '20 at 11:43
  • Could you maybe change your example? I have zero clue how to call this function. I am trying `fun test() { myExceptionCode }.catch()` but it does not work – Andrew Jan 28 '21 at 23:45
  • @Andrew I'll look at changing it soon. It concerns me a bit that people are trying to use it raw. It's meant as a proof of concept to give people a starting point to write their own helper functions. It definitely needs to be cleaned up--mainly removing the lambda extension since that is probably a point of confusion. – Aro Feb 08 '21 at 18:52
0

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

Mark Kowalski
  • 264
  • 2
  • 9
  • What's the reason of "-1"? try { ... } catch (X | Y e) { ... } in Java also checks the inheritance. This answer mimics the Java's behaviour, it's more convenient for example for catching IOException with many different subtypes. – Dmitry Ovchinnikov Jan 06 '21 at 16:23
-1

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
}
-3

In Kotlin you can do this:

try{
} catch(e: MyException1){
} catch(e: MyException2){
} catch(e: MyException3){
} [...]
RFM
  • 107
  • 7
  • 3
    This is obvious but it requires you to have separate catch block for each exception. However the idea of multi-catching is to have single catch block for a set of exceptions – Nikolai Shevchenko Sep 10 '21 at 06:46
  • 1
    True but it's no worse than the other answers on this question. What a massive oversight in the language. – mjaggard Jun 20 '22 at 16:40
  • 2
    It _is_ obviously worse because it doesn't _answer_ the question at all. – hldev Jan 19 '23 at 17:05
  • The question is "How to catch many exceptions at the same time in Kotlin?". This answers how do do that. This answer is actually is a better answer because it avoids broad exception catching like e: Exception. This is the way language designed. – Sermilion Mar 16 '23 at 08:00