How to catch many exceptions at the same time in Kotlin?
KotlinExceptionKotlin 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){
} [...]