Cómo detectar muchas excepciones al mismo tiempo en Kotlin

84
try { 

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

o

try { 

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

Como resultado, un error de compilación: Unresolved reference: MyException2.

¿Cómo puedo detectar muchas excepciones al mismo tiempo en Kotlin?

Ant20
fuente

Respuestas:

95

Actualización: vote por el siguiente número KT-7128 si desea que esta función llegue a Kotlin.Gracias @Cristan

Según este hilo, esta función no es compatible en este momento.

abreslav - Equipo JetBrains

No por el momento, pero está sobre la mesa.

Sin embargo, puede imitar la captura múltiple:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}
miensol
fuente
2
Estoy copiando la pdvriezerespuesta aquí: 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
1
@IARI La elsecláusula vuelve a generar la excepción no deseada .
miensol
2
Incluso si descarta los argumentos de elegancia y fealdad a un lado, Kotlin (que dice ser conciso) es en realidad el doble de detallado que Java en este caso
Phileo99
2
Detekt lo marca porque está detectando una excepción demasiado genérica ;-)
kenyee
8

Para agregar a la respuesta de miensol : aunque la captura múltiple en Kotlin aún no es compatible, hay más alternativas que deben mencionarse.

Aparte de try-catch-when, también puede implementar un método para imitar una captura múltiple. Aquí tienes una opción:

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

Y usarlo se vería así:

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

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

Querrá usar una función para producir una lambda en lugar de usar una lambda sin procesar como se muestra arriba (de lo contrario, se encontrará con "MANY_LAMBDA_EXPRESSION_ARGUMENTS" y otros problemas con bastante rapidez). Algo como fun attempt(block: () -> Unit) = blockfuncionaría.

Por supuesto, es posible que desee encadenar objetos en lugar de lambdas para componer su lógica de manera más elegante o para comportarse de manera diferente a un simple try-catch.

Solo recomendaría usar este enfoque en lugar de miensol si está agregando alguna especialización . Para usos simples de captura múltiple, una whenexpresión es la solución más simple.

Aro
fuente
Si lo entiendo correctamente, pasa clases en su captura, pero param exceptionstoma objetos.
nllsdfx
eres increíble hombre @aro, gracias por brindar esta alternativa
mochadwi
Esta alternativa es buena, gracias Aro :) Mejor que nada. Sin embargo, espero que lleguen a esa función, aunque mi problema KT-7128 se abrió hace 5 años :-)
zdenda.online
-1

El ejemplo de aro es muy bueno, pero si hay herencias, no funcionará como en Java.

Su respuesta me inspiró a escribir una función de extensión para eso. Para permitir también clases heredadas, debe verificar en instancelugar de comparar directamente.

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

Para ver cómo se usa, puede echar un vistazo a mi biblioteca en GitHub aquí

Mark Kowalski
fuente