Jak złapać wiele wyjątków jednocześnie w Kotlinie

87
try { 

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

lub

try { 

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

W wyniku tego błędu kompilacji: Unresolved reference: MyException2.

Jak mogę złapać wiele wyjątków w tym samym czasie na Kotlinie?

Ant20
źródło

Odpowiedzi:

100

Aktualizacja: Zagłosuj na następujący numer KT-7128, jeśli chcesz, aby ta funkcja wylądowała w Kotlinie. Dzięki @Cristan

Zgodnie z tym wątkiem ta funkcja nie jest obecnie obsługiwana.

abreslav - Zespół JetBrains

Nie w tej chwili, ale jest na stole

Możesz jednak naśladować multi-catch:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}
miensol
źródło
2
Jestem kopiowanie pdvriezeodpowiedź tutaj: 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 elseKlauzula ponownie zgłasza niechciany wyjątek.
miensol
2
Nawet jeśli odrzucisz na bok argumenty elegancji i brzydoty, Kotlin (który twierdzi, że jest zwięzły) jest w tym przypadku w rzeczywistości 2x tak gadatliwy jak Java
Phileo99
2
To zostaje oznaczone przez Detekt, ponieważ łapiesz zbyt ogólny wyjątek ;-)
kenyee
8

Aby dodać do odpowiedzi miensol : chociaż multi-catch w Kotlinie nie jest jeszcze obsługiwany, istnieje więcej alternatyw, o których należy wspomnieć.

Oprócz tego try-catch-whenmożna również zaimplementować metodę naśladowania wielokrotnego przechwytywania. Oto jedna opcja:

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

A użycie tego wyglądałoby tak:

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

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

Będziesz chciał użyć funkcji do wytworzenia lambda zamiast używać surowej lambdy, jak pokazano powyżej (w przeciwnym razie dość szybko napotkasz „MANY_LAMBDA_EXPRESSION_ARGUMENTS” i inne problemy). Coś takiego fun attempt(block: () -> Unit) = blockmogłoby zadziałać.

Oczywiście możesz chcieć łączyć obiekty zamiast lambd, aby skomponować swoją logikę bardziej elegancko lub zachowywać się inaczej niż zwykły stary try-catch.

Zalecałbym używanie tego podejścia zamiast miensol , jeśli dodajesz jakąś specjalizację . W przypadku prostych zastosowań typu multi-catch whennajprostszym rozwiązaniem jest wyrażenie.

Aro
źródło
Jeśli dobrze rozumiem, zaliczasz zajęcia w swoim catch, ale param exceptionsprzyjmuje obiekty.
nllsdfx
jesteś niesamowity man @aro, dzięki za udostępnienie tej alternatywy
mochadwi
Ta alternatywa jest dobra, dzięki Aro :) Lepiej niż nic. Mam jednak nadzieję, że do tej funkcji dojdą, chociaż mój numer KT-7128 został otwarty 5 lat temu :-)
zdenda.online 26.04.2020
0

Przykład z aro jest bardzo dobry, ale jeśli istnieją spadki, nie będzie działać tak, jak w Javie.

Twoja odpowiedź zainspirowała mnie do napisania funkcji rozszerzenia. Aby zezwolić na klasy dziedziczone, musisz sprawdzać, instancea nie bezpośrednio porównywać.

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

Aby zobaczyć, jak korzystać, możesz zajrzeć do mojej biblioteki na GitHub tutaj

Mark Kowalski
źródło
Jaki jest powód „-1”? try {...} catch (X | Y e) {...} w Javie również sprawdza dziedziczenie. Ta odpowiedź naśladuje zachowanie Javy, jest wygodniejsza na przykład do przechwytywania IOException z wieloma różnymi podtypami.
Dmitry Ovchinnikov