【问题标题】:How to catch many exceptions at the same time in Kotlin?如何在 Kotlin 中同时捕获多个异常?
【发布时间】:2016-08-14 02:48:22
【问题描述】:
try { 

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

try { 

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

结果出现编译错误:Unresolved reference: MyException2

如何在 Kotlin 上同时捕获多个异常?

【问题讨论】:

    标签: kotlin exception


    【解决方案1】:

    更新: 如果您希望此功能登陆 Kotlin,请投票支持以下问题 KT-7128感谢@Cristan

    根据thread,目前不支持此功能。

    abreslav - JetBrains 团队

    暂时没有,但已经摆在桌面上

    不过,您可以模仿多重捕获:

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

    【讨论】:

    • 我在复制pdvrieze在这里回复: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)
    • @IARI else 子句重新抛出 unwanted 异常。
    • 即使抛开优雅和丑陋的争论,在这种情况下,Kotlin(声称简洁)实际上是 Java 的 2 倍
    • 这会被 Detekt 标记,因为您捕获的异常太笼统 ;-)
    【解决方案2】:

    补充 miensol 的回答:虽然 Kotlin 中的 multi-catch 尚不支持,但还有更多的替代方案需要提及。

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

    您需要使用函数来生成 lambda,而不是使用如上所示的原始 lambda(否则您将很快遇到“MANY_LAMBDA_EXPRESSION_ARGUMENTS”和其他问题)。像fun attempt(block: () -&gt; Unit) = block 这样的东西会起作用。

    当然,您可能希望链接对象而不是 lambda,以便更优雅地组合逻辑或表现得与普通的旧 try-catch 不同。

    如果您要添加一些专业化,我只建议在 miensol 上使用这种方法。对于简单的多捕获使用,when 表达式是最简单的解决方案。

    【讨论】:

    • 如果我理解正确,您在 catch 中传递类,但参数 exceptions 接受对象。
    • 你是个很棒的人@aro,感谢您提供这个替代方案
    • 这个选择很好,谢谢 Aro :) 总比没有好。但是,尽管我的问题 KT-7128 是 5 年前打开的,但我希望他们能够使用该功能 :-)
    • 你可以改变你的例子吗?我对如何调用这个函数一无所知。我正在尝试fun test() { myExceptionCode }.catch(),但它不起作用
    • @Andrew 我会尽快改变它。我有点担心人们试图直接使用它。它旨在作为概念证明,为人们提供编写自己的辅助函数的起点。它肯定需要清理——主要是删除 lambda 扩展,因为这可能是一个混淆点。
    【解决方案3】:

    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 上的库here

    【讨论】:

    • “-1”是什么原因? Java 中的 try { ... } catch (X | Y e) { ... } 也会检查继承。这个答案模仿了 Java 的行为,例如捕获具有许多不同子类型的 IOException 更方便。
    【解决方案4】:

    这样你可以获取多个 Catch 并且使用 MultiCatch 方法可以检测异常

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

    这是 multiCatch()

    fun <R> Exception.multiCatch(vararg classes: KClass<*>, block: () -> R): R {
            return if (classes.any {
                    this::class.isSubclassOf(it)
                }) block()
            else throw this
    }
    

    【讨论】:

      【解决方案5】:

      在 Kotlin 中你可以这样做:

      try{
      } catch(e: MyException1){
      } catch(e: MyException2){
      } catch(e: MyException3){
      } [...]
      

      【讨论】:

      • 这很明显,但它要求您为每个异常设置单独的 catch 块。然而,多捕获的想法是为一组异常设置单个捕获块
      猜你喜欢
      • 2013-01-31
      • 2021-09-09
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 2020-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多