Як зловити багато винятків одночасно в Котліні


88
try { 

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

або

try { 

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

В результаті, помилка компіляції: Unresolved reference: MyException2.

Як я можу зловити багато винятків одночасно на Kotlin?

Відповіді:


101

Оновлення: Проголосуйте за наступний випуск KT-7128, якщо ви хочете, щоб ця функція потрапила в Котлін. Дякую @Cristan

Відповідно до цієї теми ця функція наразі не підтримується.

abreslav - команда JetBrains

Не зараз, але це на столі

Ви можете імітувати мульти-улов, хоча:

try {
    // do some work
} catch (ex: Exception) {
    when(ex) {
        is IllegalAccessException, is IndexOutOfBoundsException -> {
            // handle those above
        }
        else -> throw ex
    }
}

2
Я 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)
копіюю

1
@IARI elseЗастереження відновлює небажаний виняток.
miensol


2
Навіть якщо відкинути аргументи елегантності та потворності, Котлін (який стверджує, що він лаконічний) насправді вдвічі детальніший, ніж Java, у цьому випадку
Phileo99,

2
Це повідомляє Detekt, оскільки ви
вловлюєте

8

Додайте до відповіді miensol : хоча мульти-улов у Котліні ще не підтримується, існує більше альтернатив, про які слід згадати.

Окрім try-catch-when, ви також можете реалізувати метод, що імітує мульти-улов. Ось один із варіантів:

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

І використання цього буде виглядати так:

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

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

Вам потрібно буде використовувати функцію для створення лямбда, а не використовувати необроблену лямбду, як показано вище (інакше досить швидко натрапите на "MANY_LAMBDA_EXPRESSION_ARGUMENTS" та інші проблеми). Щось на зразок fun attempt(block: () -> Unit) = blockспрацювало б.

Звичайно, ви можете захотіти об’єднати об’єкти замість лямбд, щоб скласти свою логіку більш елегантно або поводитися не так, як звичайна стара спроба.

Я рекомендував би використовувати цей підхід у порівнянні з miensol , лише якщо ви додаєте певну спеціалізацію . Для простих багатокористувацьких застосувань whenвираз є найпростішим рішенням.


Якщо я правильно розумію, ви проходите класи з вашого улову, але param exceptionsбере об'єкти.
nllsdfx

ти чудовий чоловік @aro, дякую за надання цієї альтернативи
mochadwi

Ця альтернатива хороша, дякую Аро :) Краще, ніж нічого. Однак, я сподіваюся, вони
досягнуть

0

Приклад з aro дуже хороший, але якщо є спадщини, він не буде працювати, як у Java.

Ваша відповідь надихнула мене написати для цього функцію розширення. Щоб також дозволити успадковані класи, вам потрібно перевірити, instanceзамість порівняння безпосередньо.

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

Щоб побачити, як користуватися, ви можете заглянути в мою бібліотеку на GitHub тут


У чому причина "-1"? спробуйте {...} catch (X | Y e) {...} у Java також перевіряє спадщину. Ця відповідь імітує поведінку Java, вона більш зручна, наприклад, для лову IOException з багатьма різними підтипами.
Дмитро Овчинников
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.