欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > Kotlin 2.1.0 入门教程(十二)异常

Kotlin 2.1.0 入门教程(十二)异常

2025/2/11 6:19:26 来源:https://blog.csdn.net/qq_19661207/article/details/145532919  浏览:    关键词:Kotlin 2.1.0 入门教程(十二)异常

异常

Kotlin 默认将所有异常视为未检查异常。未检查异常简化了异常处理过程:可以捕获异常,但不需要显式处理或声明它们。

异常由 Exception 类的子类表示,而 Exception 类是 Throwable 类的子类。由于 Exception 是一个开放类(open class),您可以创建自定义异常以满足应用程序的特定需求。

抛出异常

您可以使用 throw 关键字手动抛出异常。抛出异常表示代码中发生了意外的运行时错误。异常是对象,抛出异常时会创建异常类的一个实例。

您可以抛出一个不带任何参数的异常:

throw IllegalArgumentException()

为了更好地理解问题的根源,可以包含额外的信息,例如自定义消息和原始原因:

val cause = IllegalStateException("Original cause: illegal state")// 如果 userInput 为负数,则抛出 IllegalArgumentException 异常。
// 同时显示原始原因,由 cause IllegalStateException 表示。
if (userInput < 0) {throw IllegalArgumentException("Input must be non-negative", cause)
}

使用前置条件函数抛出异常

Kotlin 提供了额外的方式,通过前置条件函数自动抛出异常。前置条件函数包括:

前置条件函数用例抛出的异常
require()检查用户输入的有效性IllegalArgumentException
check()检查对象或变量状态的有效性IllegalStateException
error()指示非法状态或条件IllegalStateException

这些函数适用于在特定条件未满足时程序无法继续执行的情况。这种方式可以简化代码,并使处理这些检查更加高效。

使用 require() 函数来验证输入参数,当这些参数对函数的操作至关重要且如果参数无效时函数无法继续执行时。如果 require() 中的条件未满足,它会抛出 IllegalArgumentException 异常:

fun getIndices(count: Int): List<Int> {require(count >= 0) { "Count must be non-negative. You set count to $count." }return List(count) { it + 1 }
}fun main() {// 这将失败并抛出 IllegalArgumentException 异常。println(getIndices(-1))
}

require() 函数允许编译器执行智能转换。在检查成功后,变量会自动转换为非空类型。这些函数通常用于空值检查,以确保在继续操作之前变量不为空。例如:

fun printNonNullString(str: String?) {require(str != null)println(str.length)
}

使用 check() 函数来验证对象或变量的状态。如果检查失败,则表明存在需要解决的逻辑错误。如果 check() 函数中指定的条件为 false,它会抛出 IllegalStateException 异常:

fun main() {var someState: String? = nullfun getStateValue(): String {val state = checkNotNull(someState) { "State must be set beforehand!" }check(state.isNotEmpty()) { "State must be non-empty!" }return state}// 如果您取消注释下面行,程序将因 IllegalStateException 异常而失败。// getStateValue()someState = ""// 如果您取消注释下面行,程序将因 IllegalStateException 异常而失败。// getStateValue()someState = "non-empty-state"println(getStateValue()) // non-empty-state
}

check() 函数允许编译器执行智能转换。在检查成功后,变量会自动转换为非空类型。这些函数通常用于空值检查,以确保在继续操作之前变量不为空。例如:

fun printNonNullString(str: String?) {check(str != null)println(str.length)
}

error() 函数用于表示代码中的非法状态或逻辑上不应发生的条件。它适用于您希望在代码中故意抛出异常的场景,例如当代码遇到意外状态时。此函数在 when 表达式中特别有用,为处理逻辑上不应发生的情况提供了一种清晰的方式。

在以下示例中,error() 函数用于处理未定义的用户角色。如果角色不是预定义的角色之一,则会抛出 IllegalStateException 异常:

class User(val name: String, val role: String)fun processUserRole(user: User) {when (user.role) {"admin" -> println("${user.name} is an admin.")"editor" -> println("${user.name} is an editor.")"viewer" -> println("${user.name} is a viewer.")else -> error("Undefined role: ${user.role}")}
}fun main() {val user1 = User("Alice", "admin")processUserRole(user1) // Alice is an admin.// 抛出 IllegalStateException 异常。val user2 = User("Bob", "guest")processUserRole(user2)
}

使用 try-catch 块处理异常

当抛出异常时,它会中断程序的正常执行。您可以使用 trycatch 关键字优雅地处理异常,以保持程序的稳定性。try 块包含可能抛出异常的代码,而 catch 块捕获并处理发生的异常。异常会被第一个匹配其特定类型或异常超类的 catch 块捕获。

try {// 可能抛出异常的代码。
} catch (e: SomeException) {// 处理异常的代码。
}

一种常见的方法是将 try-catch 用作表达式,这样它可以从 try 块或 catch 块返回值:

fun main() {val num: Int = try {// 如果 count() 成功执行,其返回值将赋给 num。count()} catch (e: ArithmeticException) {// 如果 count() 抛出异常,catch 块返回 -1,并将其赋给 num。-1}
}fun count(): Int {return 10 / 0
}

您可以为同一个 try 块使用多个 catch 处理程序。可以根据需要添加任意数量的 catch 块,以区分处理不同的异常。当有多个 catch 块时,重要的是按照从最具体到最不具体异常的顺序排列它们,遵循代码中的从上到下的顺序。这种排序与程序的执行流程一致。

open class WithdrawalException(message: String) : Exception(message)
class InsufficientFundsException(message: String) : WithdrawalException(message)fun processWithdrawal(amount: Double, availableFunds: Double) {if (amount > availableFunds) {throw InsufficientFundsException("Insufficient funds for the withdrawal.")}if (amount < 1 || amount % 1 != 0.0) {throw WithdrawalException("Invalid withdrawal amount.")}println("Withdrawal processed")
}fun main() {val availableFunds = 500.0val withdrawalAmount = 500.5try {processWithdrawal(withdrawalAmount.toDouble(), availableFunds)} catch (e: InsufficientFundsException) {println("Caught an InsufficientFundsException: ${e.message}")} catch (e: WithdrawalException) {println("Caught a WithdrawalException: ${e.message}")}
}

一个处理 WithdrawalException 的通用 catch 块会捕获其类型的所有异常,包括像 InsufficientFundsException 这样的特定异常,除非它们被更具体的 catch 块提前捕获。

finally

finally 块包含的代码无论 try 块是成功完成还是抛出异常都会执行。通过 finally 块,您可以在 trycatch 块执行后进行清理操作。这在处理文件或网络连接等资源时尤为重要,因为 finally 可以确保它们被正确关闭或释放。

// error
// finally
fun main() {try {error("error")}catch (e: Exception) {println(e.message)}finally {println("finally")}    
}
// finally
fun main() {try {}catch (e: Exception) {println(e.message)}finally {println("finally")}    
}

try 表达式的返回值由 trycatch 块中最后执行的表达式决定。如果没有发生异常,结果来自 try 块;如果处理了异常,则结果来自 catch 块。finally 块总是会执行,但它不会改变 try-catch 块的结果。

fun divideOrNull(a: Int): Int {try {val b = 44 / aprintln("try block: Executing division: $b")return b}catch (e: ArithmeticException) {println("catch block: Encountered ArithmeticException $e")return -1}finally {println("finally block: The finally block is always executed")}
}fun main() {// catch block: Encountered ArithmeticException java.lang.ArithmeticException: / by zero// finally block: The finally block is always executed// -1println(divideOrNull(0))// try block: Executing division: 44// finally block: The finally block is always executed// 44println(divideOrNull(1))
}

Kotlin 中,管理实现了 AutoClosable 接口的资源(例如 FileInputStreamFileOutputStream 等文件流)的惯用方法是使用 use 函数。该函数在代码块执行完成后自动关闭资源,无论是否抛出异常,从而无需使用 finally 块。

FileWriter("test.txt").use { writer ->writer.write("some text")// 在这个代码块之后,use 函数会自动调用 writer.close(),类似于 finally 块的作用。
}

如果您的代码需要进行资源清理而不处理异常,您也可以使用 tryfinally 块,而不使用 catch 块:

try {resource.use()
} finally {resource.close()
}

如您所见,finally 块保证了无论是否发生异常,资源都会被关闭。

Kotlin 中,您可以根据具体需求灵活地仅使用 catch 块、仅使用 finally 块,或者两者都使用,但 try 块必须始终至少伴随一个 catch 块或 finally 块。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com