<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## **[異常](http://www.hmoore.net/alex_wsc/android_kotlin/1318345)處理** [TOC] ### **異常概述** 什么是異常?說到異常處理,我們想到了try、catch、finally 這樣的3個關鍵字,是的,Kotlin里面也是這樣的3個關鍵字,意義和Java也是一樣的。我們對可能出現異常的語句使用try語句塊包裹,如果try里面的語句真的出現了異常,代碼將會跳轉到catch語句塊里面。無論代碼執行順序如何,最終都會走到finally語句塊中。 Kotlin 中所有異常類都是 Throwable 類的子孫類。 每個異常都有消息、堆棧回溯信息和可選的原因。 示例 ``` fun divide(a: Int, b: Int): Int { var result: Int = a / b //定義一個result變量用于存放a/b的值 return result //將結果返回 } fun main(args: Array<String>) { var result = divide(5, 0) //調用divide()方法 println(result) } ``` 運行結果 ``` Exception in thread "main" java.lang.ArithmeticException: / by zero at FileKt.divide (File.kt:2) at FileKt.main (File.kt:7) ``` 從運行結果可知,程序在運行過程中拋出一個算術異常(ArithmeticException),這個異常是因為程序的第6行代碼中,調用divide()方法時第2個參數傳入了0,當程序執行第3行代碼時出現了被0除的錯誤。出現這個異常之后,程序會立即結束,不會再執行下面的其他代碼。 ArithmeticException異常類只是Kotlin異常類中的一種,在Kotlin中還提供了其他異常類,如ClassNotFoundException、ArrayIndexOutOfBoundsException、IllegalArgumentException等,這些類都繼承自java.lang.Throwable類。 要拋出異常可以使用 throw -表達式來拋出異常。 ``` throw MyException("Hi There!") ``` 要捕獲異常,可以使用try表達式 ``` try { // 一些代碼 } catch (e: SomeException) { // 處理程序 } finally { // 可選的 finally 塊 } ``` >[info]注意: ①、try表達式可以有0到多個 catch 塊。 finally 塊可以省略。 但是 catch 和 finally 塊至少應該存在一個。 ②、在Kotlin中, throw和try都是表達式,這意味著它們可以被賦值給一個變量。這個在處理一些邊界問題的時候確實非常有用 ### try…catch和finally Kotlin中提供了一種對異常進行處理的方式——**異常捕獲**。異常捕獲通常使用try…catch語句來實現,異常捕獲的語法格式如下: ``` try { // 程序代碼 }catch (e: SomeException) { // e: 后面的這個類可以是Exception 類或者其子類 // 對捕獲的Exception 進行處理 } ``` 上述語法格式中,try代碼塊中編寫的是可能發生異常的Kotlin語句,catch代碼塊中編寫的是對捕獲的異常進行處理的代碼。當try代碼塊中的程序發生了異常,系統會將這個異常的信息封裝成一個異常對象,并將這個對象傳遞給catch代碼塊。catch代碼塊中傳遞的Exception類型的參數是指定這個程序能夠接收的異常類型,這個參數的類型必須是Exception類或者其子類。 * **示例** ``` fun divide(a: Int, b: Int): Int { var result: Int = a / b //定義一個result變量用于存放a/b的值 return result //將結果返回 } fun main(args: Array<String>) { try { var result: Int = divide(5, 0) println(result) } catch (e: Exception) { println("捕獲的異常信息為:" + e.message) } println("程序繼續執行") } ``` 運行結果 ``` 捕獲的異常信息為:/ by zero 程序繼續執行 ``` 在上述代碼中,對可能發生異常的代碼用try…catch語句進行了處理,在try代碼塊中發生被0除異常之后,程序會接著執行catch中的代碼,通過調用Exception對象中的message來返回異常信息“by/zero”,catch代碼塊對異常處理完畢之后,程序會繼續向下執行,而不會出現異常終止。 >[info]需要注意的是,在try代碼塊中,發生異常的語句后面的代碼是不會被執行的,如本案例中的第8行代碼的輸出語句就沒有執行。 在程序中,由于功能的需求,有些語句在無論程序是否發生異常的情況下都要執行,這時就可以在try…catch語句后添加一個finally代碼塊。接下來我們來對上面的代碼進行修改,看一下finally代碼塊的用法,具體代碼如下所示。 ``` fun divide(a: Int, b: Int): Int { var result: Int = a / b //定義一個result變量用于存放a/b的值 return result //將結果返回 } fun main(args: Array<String>) { try { var result: Int = divide(5, 0) //調用divide()方法 println(result) } catch (e: Exception) { println("捕獲的異常信息為:" + e.message) return //用于結束當前語句 } finally { println("進入finally代碼塊") } println("程序繼續執行") } ``` 運行結果 ``` 捕獲的異常信息為:/ by zero 進入finally代碼塊 ``` 在上述代碼中,catch代碼塊中增加了一個return語句,用于結束當前方法,此時第15行的代碼`println("程序繼續執行")`就不會執行了,而finally中的代碼仍會執行,并不會被return語句所影響。 不論程序發生異常還是用return語句結束當前方法,finally中的語句都會執行,由于finally語句的這種特殊性,因此在程序設計時,經常會在try…catch后使用finally代碼塊來完成必須做的事情,如釋放系統資源。 >[info]需要注意的是,當catch代碼塊中執行了System.exit(0)語句時,finally中的代碼塊就不會執行。System.exit(0)表示退出當前的程序,退出當前程序后,任何代碼都不能再執行了。 #### 與Java中的try…catch…finally對比 與Java不同的是,**在try…catch…finally中,try是一個表達式,即它可以返回一個值,try表達式的返回值是try代碼塊中的最后一個表達式的結果或者是所有catch代碼塊中的最后一個表達式的結果,finally代碼塊中的內容不會影響表達式的結果**。接下來我們通過一個案例來演示try…catch…finally代碼塊中的結果,代碼如下所示 ``` fun main(args: Array<String>) { var age: Int? = try { 10 //正常運行,返回10 } catch (e: NumberFormatException) { 12 null } finally { 13 //finally代碼塊不會影響表達式結果 } var score: Int? = try { Integer.parseInt("s" + 1) } catch (e: NumberFormatException) { 60 null //捕獲異常,返回null } finally { 70 //finally代碼塊不會影響表達式結果 } println("年齡age=${age}") println("分數score=${score}") } ``` 運行結果 ``` 年齡age=10 分數score=null ``` 上述代碼中,分別定義了2個變量age與score,age表示年齡,score表示分數,這2個變量的值都是用try…catch…finally代碼塊包括起來的,根據程序的運行結果可知,當給變量age賦值時,程序正常運行,則age的值是10,即try表達式的結果。當給變量score賦值時,程序出現了異常(s不知從何而來,Integer是Java中的類,字符串默認值是null,即為空未分配對象,看Integer源碼就知道,Integer.parseInt方法參數為null時,`throw new NumberFormatException("null")`),此時score的值是null,即catch代碼塊中最后一個表達式的結果。其中finally代碼塊中的內容不影響try和catch代碼塊中表達式的結果。 總結: 在try…catch…finally語句中,catch代碼塊可以有多個也可以沒有,finally代碼塊可以省略,但是catch和finally代碼塊至少應有一個是存在的。 #### **Try 是?個表達式,可以有一個返回值** 【Kotlin相比于Java,可以使用變量try表達式返回值】。try表達式要么有try語句塊的最后一行決定,要么由catch語句塊的最后一行決定;finally代碼段的內容不會影響try表達式的結果值。參考如下代碼: ![](https://box.kancloud.cn/d641eb1949151aad0704404c1f337dcc_984x627.png) 針對以上代碼,如果try語句塊沒有異常,返回的就是字符串轉換轉換的結果,如果出現異常,就會走到catch語句塊,返回的就是0。 運行結果: ![](https://box.kancloud.cn/e5d4ef9fa7248b21126d2a96df34c5d6_979x123.png) ### **throw表達式** 前面的代碼中,由于調用的是自己寫的divide()方法,因此很清楚該方法可能會發生異常。試想一下,如果去調用一個別人寫的方法時,是否能知道別人寫的方法是否會有異常呢?這是很難做出判斷的。針對這種情況,在Kotlin中,允許在可能發生異常的代碼中通過throw關鍵字對外聲明該段代碼可能會發生異常,這樣在使用這段代碼時,就明確地知道該段代碼有異常,并且必須對異常進行處理。 throw關鍵字拋出異常的語法格式如下: ``` throw ExceptionType("異常信息") ``` 上述語法格式是通過throw表達式來拋出一個異常,這個表達式需要放在容易出現異常的代碼中,也可以作為Elvis表達式(三元表達式)的一部分,throw后面需要聲明發生異常的類型,通常將這種做法稱為拋出一個異常。接下來我們來修改前面的代碼,在調用divide()方法的代碼上方拋出一個異常,修改后的代碼如下所示 ``` fun divide(a: Int, b: Int): Int { if (b==0)throw ArithmeticException("發生異常") var result: Int = a / b return result } fun main(args: Array<String>) { var result: Int = divide(5, 0) //調用divide()方法 println(result) } ``` 報錯如下 ``` Exception in thread "main" java.lang.ArithmeticException: 發生異常 at FileKt.divide (File.kt:2) at FileKt.main (File.kt:7) ``` 上述代碼中,第7行代碼調用divide()方法時傳遞的第2個參數是0,程序在運行時不會發生被0除的異常,由于在divide()方法中拋出了一個算術異常ArithmeticException,因此在調用divide()方法時就必須對拋出的異常進行處理,否則就會發生編譯錯誤。接下來我們對代碼進行修改,在調用divide()方法時對其進行try…catch處理,修改后的代碼如下所示。 ``` fun divide(a: Int, b: Int): Int { if (b==0)throw ArithmeticException("發生異常") var result: Int = a / b return result } fun main(args: Array<String>) { try { var result: Int = divide (5, 0) //調用divide()方法 println(result) } catch (e: ArithmeticException) { println(e.message) } } ``` 運行結果 ``` 發生異常 ``` 上述代碼中,在main()函數中通過try…catch語句已經捕獲了divide()方法中拋出的異常,由于該程序的divide()方法中傳遞的變量b的值為0,因此運行結果為發生異常。如果將變量b的值設置為1,則運行結果為5。 #### 用于Elvis 表達式的?部分 在 Kotlin 中 throw 是表達式,所以你可以使?它(?如)作為 Elvis 表達式的?部分: ``` val s = person.name ?: throw IllegalArgumentException("Name required") ``` #### Nothing類型 參考后面的章節——[kotlin.Nothing類型](http://www.hmoore.net/alex_wsc/android_kotlin/1053641)和官方文檔[Nothing 類型](http://www.kotlincn.net/docs/reference/exceptions.html#nothing-%E7%B1%BB%E5%9E%8B) 在 Kotlin 中 throw 是表達式,它的類型是特殊類型 Nothing。 該類型沒有值。跟C、Java中的 void 意思一樣,?是?于標記永遠不能達到的代碼位置。 在Kotlin中,有些函數的“返回值類型”的概念沒有任何意義,此時Kotlin使用一種特殊的返回值類型Nothing來表示,Nothing是一個空類型(uninhabited type),也就是說在程序運行時不會出任何一個Nothing類型的對象。在程序中,可以使用Nothing類型來標記一個永遠不會有返回數據的函數, 我們在代碼中,用 Nothing 來標記無返回的函數: ~~~ fun main(args: Array<String>) { fail("Error occurred") } fun fail(message:String):Nothing{ throw IllegalStateException(message) } ~~~ 當調用含有Nothing類型的函數時,可能會遇到這個類型的一種情況就是類型推斷,這個類型的可空類型為Nothing?,該類型有一個可能的值是null,如果用null來初始化一個變量的值,并且又不能確定該變量的具體類型時,編譯器會推斷這個變量的類型為Nothing?類型,具體示例代碼如下: ``` val x = null // 變量“x”的類型為“Nothing? ” val l = listOf(null) // 變量“l”的類型為“List<Nothing?>” ``` 上述代碼中,變量x的初始值為null,并且該變量的具體類型不確定,因此編譯器會推斷該變量的類型為“Nothing?”。變量l的初始值為listOf(null),可以看到List集合的初始值為null,此時不能確定該集合的具體類型,因此編譯器會推斷該集合的類型為“List<Nothing?>”。 * 另外,如果把一個throw表達式的值賦值給一個變量,需要顯式聲明類型為 Nothing , ``` val ex:Nothing = throw Exception("YYYYYYYY") ``` >[info]【注意】另外,因為ex變量是Nothing類型,沒有任何值,所以無法當做參數傳給函數 可能會遇到這個類型的另?種情況是類型推斷。這個類型的可空變體 Nothing? 有?個可能的值是 null 。如果? null 來初始化?個要推斷類型的值,??沒有其他信息可?于確定更具體的類型時,編譯器會推斷出 Nothing? 類型: ``` val x = null // “x”具有類型 `Nothing?` val l = listOf(null) // “l”具有類型 `List<Nothing?> ``` ### **沒有受檢異常** **Kotlin沒有受檢異常(Checked Exceptions)**。 Java里面有兩種異常類型,一種是受檢異常(checked exception),一種是非受檢異常(uncheckedexception)。 之所以編寫Java代碼的時候,IDE會提示進行try catch操作,因為編譯時編譯器會檢查受檢異常。 受檢異常(Checked Exceptions)顯得比較麻煩,一直以來爭議比較大,可能會導致java API變得復雜,程序員編寫代碼的時候需要進行大量的try catch操作。所以,【Kotlin相比于Java,沒有了受檢異常,IDE不會提示進行try catch操作】。 寫代碼的時候,IDE調用某一個方法,這個方法即使可能拋出異常,IDE也不會提示你進行`try…catch`操作,直接運行該程序時會拋出異常信息。參考如下代碼: ![](https://box.kancloud.cn/b6267b3d90998baa9b7de986f725b276_984x297.png) 針對以上代碼,如果是java代碼,【Integer.parseInt(line)】,這樣的代碼是會提示我們進行trycatch操作的,但是Kotlin不會提示。如果直接運行會拋出轉換異常,參考截圖: ![](https://box.kancloud.cn/f6b962f8694f98d2c0e3e48726494460_972x121.png) 我們可以自己給它加上try catch操作,參考如下代碼: ![](https://box.kancloud.cn/cf18dc1b6a25d0297d18a3dcdac5887b_986x766.png) * **JDK舉例** 以下是 JDK 中 StringBuilder 類實現的?個?例接?: ``` Appendable append(CharSequence csq) throws IOException; ``` 這個簽名是什么意思? 它是說,每次我追加?個字符串到?些東西(?個 StringBuilder 、某種?志、?個控制臺等)上時我就必須捕獲那些IOException 。 為什么?因為它可能正在執? IO 操作( Writer 也實現了 Appendable )…… 所以它導致這種代碼隨處可?的出現: ``` try { log.append(message) } catch (IOException e) { // 必須要安全 } ``` **結論**:通過一些小程序測試得出的結論是異常規范會同時提高開發者的生產力與代碼質量,但是大型軟件項目的經驗表明一個不同的結論——生產力降低、代碼質量很少或沒有提高。 ### 自定義異常 在Kotlin標準庫中封裝了大量的異常類,雖然這些異常類可以描述編程時出現的大部分異常情況,但是在程序開發中有時可能需要描述程序中特有的異常情況,例如在設計一個變量name的值時,不允許該變量的值為null,為了解決這個問題,Kotlin與Java一樣,也允許用戶自定義異常,但**自定義的異常類必須繼承自Throwable類或其子類**,自定義異常類的主構函數可以傳遞一個String類型的message參數,也可以不傳遞參數,自定義異常類的語法格式如下: ``` //主構函數帶參數的異常類 class異常類名稱(override val message: String?) : Throwable() {} //主構函數不帶參數的異常類 class異常類名稱() : Throwable() {} ``` 在上述語法格式中,主構造函數帶message參數的異常類,在拋出異常信息時會打印message信息,主構造函數不帶message參數的異常類,在拋出異常信息時不會打印異常的具體信息。 示例 ``` class MyException(override val message: String?) : Throwable() { } fun main(args: Array<String>) { var name: String? = null name?.length ?: throw MyException("變量name的值為null") println("name.length=${name.length}") } ``` 報錯如下 ``` Exception in thread "main" MyException: 變量name的值為null at FileKt.main (File.kt:5) ``` 從運行結果可以看出,程序在運行時發生了異常,這是因為在程序中使用throw關鍵字拋出異常對象時,需要使用`try…catch`語句對拋出的異常進行處理。為了解決該程序運行時發生異常的問題,可以修改該程序,在拋出異常的地方使用`try…catch`語句對異常進行處理,修改后的代碼如下所示。 ``` class MyException(override val message: String?) : Throwable() { } fun main(args: Array<String>) { var name: String? = null try { name?.length ?: throw MyException("變量name的值為null") println("name.length=${name.length}") } catch (e: MyException) { println(e.message) } } ``` 運行結果 ``` 變量name的值為null ``` 在上述代碼中,使用了一個try…catch語句用于捕獲變量name的值為null時拋出的異常,在調用“name?.length”代碼時,由于變量name的值不能為null,程序會拋出一個自定義異常MyException,該異常被捕獲后最終被catch代碼塊處理,并打印異常信息。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看