例外處理#
例外(Exception)是程式執行時發生的錯誤事件。Kotlin 使用 try、catch、finally 來捕捉和處理例外,避免程式意外崩潰。
1. 基本語法#
1
2
3
4
5
6
7
| try {
// 可能拋出例外的程式碼
} catch (e: 例外型別) {
// 例外處理邏輯
} finally {
// 無論是否發生例外都會執行(可選)
}
|
2. 捕捉例外#
範例:除以零#
1
2
3
4
5
6
7
8
9
| fun main() {
try {
val result = 10 / 0
println(result)
} catch (e: ArithmeticException) {
println("發生算術錯誤:${e.message}")
}
// 輸出:發生算術錯誤:/ by zero
}
|
範例:字串轉數字失敗#
1
2
3
4
5
6
7
8
9
10
| fun main() {
val input = "abc"
try {
val number = input.toInt()
println("數字是:$number")
} catch (e: NumberFormatException) {
println("無法將 \"$input\" 轉換為數字")
}
// 輸出:無法將 "abc" 轉換為數字
}
|
3. finally 區塊#
finally 區塊無論例外是否發生都會執行,常用於釋放資源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| fun readFile(filename: String) {
println("開啟檔案:$filename")
try {
// 模擬可能發生的錯誤
if (filename.isEmpty()) throw IllegalArgumentException("檔名不能為空")
println("讀取成功")
} catch (e: IllegalArgumentException) {
println("錯誤:${e.message}")
} finally {
println("關閉檔案") // 一定會執行
}
}
fun main() {
readFile("data.txt")
println("---")
readFile("")
// 輸出:
// 開啟檔案:data.txt
// 讀取成功
// 關閉檔案
// ---
// 開啟檔案:
// 錯誤:檔名不能為空
// 關閉檔案
}
|
4. 捕捉多種例外#
可以使用多個 catch 區塊分別處理不同類型的例外。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| fun parse(input: String) {
try {
val number = input.toInt()
val result = 100 / number
println("結果:$result")
} catch (e: NumberFormatException) {
println("格式錯誤:\"$input\" 不是有效數字")
} catch (e: ArithmeticException) {
println("算術錯誤:不能除以零")
}
}
fun main() {
parse("abc") // 輸出:格式錯誤:"abc" 不是有效數字
parse("0") // 輸出:算術錯誤:不能除以零
parse("5") // 輸出:結果:20
}
|
5. throw:主動拋出例外#
使用 throw 可以主動拋出例外。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| fun checkAge(age: Int) {
if (age < 0) throw IllegalArgumentException("年齡不能為負數:$age")
if (age > 150) throw IllegalArgumentException("年齡超出合理範圍:$age")
println("年齡有效:$age")
}
fun main() {
try {
checkAge(25)
checkAge(-5)
} catch (e: IllegalArgumentException) {
println("輸入錯誤:${e.message}")
}
// 輸出:
// 年齡有效:25
// 輸入錯誤:年齡不能為負數:-5
}
|
6. try 作為表達式#
Kotlin 的 try 可以作為表達式,直接回傳值。
1
2
3
4
5
6
7
8
9
10
11
12
13
| fun toIntOrDefault(input: String, default: Int = 0): Int {
return try {
input.toInt()
} catch (e: NumberFormatException) {
default
}
}
fun main() {
println(toIntOrDefault("42")) // 輸出:42
println(toIntOrDefault("abc")) // 輸出:0
println(toIntOrDefault("abc", -1)) // 輸出:-1
}
|
7. 自訂例外#
繼承 Exception 類別可以建立自訂例外,提供更具語意的錯誤訊息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| class InsufficientFundsException(amount: Double) :
Exception("餘額不足,嘗試提領 $amount 元")
class BankAccount(private var balance: Double) {
fun withdraw(amount: Double) {
if (amount > balance) throw InsufficientFundsException(amount)
balance -= amount
println("提領成功,剩餘餘額:$balance 元")
}
}
fun main() {
val account = BankAccount(1000.0)
try {
account.withdraw(500.0)
account.withdraw(800.0)
} catch (e: InsufficientFundsException) {
println("交易失敗:${e.message}")
}
// 輸出:
// 提領成功,剩餘餘額:500.0 元
// 交易失敗:餘額不足,嘗試提領 800.0 元
}
|
8. 常見例外型別#
| 例外型別 | 常見原因 |
|---|
ArithmeticException | 除以零 |
NumberFormatException | 字串無法轉換為數字 |
NullPointerException | 對 null 物件呼叫方法 |
IndexOutOfBoundsException | 陣列或集合索引超出範圍 |
IllegalArgumentException | 傳入不合法的參數 |
IllegalStateException | 物件狀態不允許執行此操作 |
ClassCastException | 型別轉換失敗 |
9. Kotlin 沒有受檢例外#
Java 有 受檢例外(Checked Exception),強制要求呼叫方處理或宣告例外。Kotlin 沒有 受檢例外,所有例外都是非受檢的,讓程式碼更簡潔,但也需要開發者自行確保重要例外有被處理。
Reference#
https://kotlinlang.org/docs/exceptions.html