Wie man in Kotlin viele Ausnahmen gleichzeitig fängt

83
try { 

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

oder

try { 

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

Infolgedessen ein Kompilierungsfehler : Unresolved reference: MyException2.

Wie kann ich auf Kotlin viele Ausnahmen gleichzeitig abfangen?

Ant20
quelle

Antworten:

95

Update: Stimmen Sie für das folgende Problem KT-7128 ab, wenn diese Funktion in Kotlin landen soll. Danke @Cristan

Laut diesem Thread wird diese Funktion derzeit nicht unterstützt.

abreslav - JetBrains Team

Im Moment nicht, aber es liegt auf dem Tisch

Sie können den Multi-Catch jedoch nachahmen:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}
Miensol
quelle
2
Ich pdvriezeThis 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)
kopiere die
1
@IARI Die elseKlausel löst die unerwünschte Ausnahme erneut aus.
Miensol
2
Selbst wenn Sie die Argumente von Eleganz und Hässlichkeit beiseite werfen, ist Kotlin (der behauptet, prägnant zu sein) in diesem Fall tatsächlich 2x so ausführlich wie Java
Phileo99
2
Das wird von Detekt markiert, weil Sie eine zu generische Ausnahme
abfangen ;-)
8

Um die Antwort von miensol zu ergänzen : Obwohl Multi-Catch in Kotlin noch nicht unterstützt wird, gibt es weitere Alternativen, die erwähnt werden sollten.

Abgesehen davon try-catch-whenkönnen Sie auch eine Methode implementieren, um einen Multi-Catch nachzuahmen. Hier ist eine 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
    }
}

Und es würde so aussehen:

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

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

Sie möchten eine Funktion verwenden, um ein Lambda zu erzeugen, anstatt wie oben gezeigt ein rohes Lambda zu verwenden (andernfalls werden Sie ziemlich schnell auf "MANY_LAMBDA_EXPRESSION_ARGUMENTS" und andere Probleme stoßen). So etwas fun attempt(block: () -> Unit) = blockwürde funktionieren.

Natürlich möchten Sie vielleicht Objekte anstelle von Lambdas verketten, um Ihre Logik eleganter zu gestalten oder sich anders zu verhalten als ein einfacher alter Versuch.

Ich würde nur empfehlen, diesen Ansatz gegenüber Miensols zu verwenden , wenn Sie eine Spezialisierung hinzufügen . Für einfache Multi-Catch-Anwendungen ist ein whenAusdruck die einfachste Lösung.

Aro
quelle
Wenn ich es richtig verstehe, übergeben Sie Klassen in Ihrem Fang, aber param exceptionsnimmt Objekte.
nllsdfx
Du bist ein großartiger Mann @aro, danke, dass du diese Alternative zur Verfügung gestellt
hast
Diese Alternative ist gut, danke Aro :) Besser als nichts. Ich hoffe jedoch, dass sie diese Funktion nutzen können, obwohl meine Ausgabe KT-7128 vor 5 Jahren geöffnet wurde :-)
zdenda.online
-1

Das Beispiel von aro ist sehr gut, aber wenn es Vererbungen gibt, funktioniert es nicht wie in Java.

Ihre Antwort hat mich dazu inspiriert, eine Erweiterungsfunktion dafür zu schreiben. Um auch geerbte Klassen zuzulassen, müssen Sie suchen, instanceanstatt direkt zu vergleichen.

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

Um zu sehen , wie zu benutzen, können Sie einen Blick in meiner Bibliothek auf GitHub haben hier

Mark Kowalski
quelle