異常處理

Kotlin 的異常處理機(jī)制主要依賴于try、catch、finally、throw 這四個(gè)關(guān)鍵字类垦,其中try關(guān)鍵字后緊跟一個(gè)用花括號(hào)括起來的代碼塊(花括號(hào)不可省略),簡(jiǎn)稱try塊坦弟,它里面放置可能引發(fā)異常的代碼护锤。 catch 后對(duì)應(yīng)異常類型和一個(gè)代碼塊,表明該 catch 塊用于處理這種類型的代碼塊酿傍。 多個(gè)catch塊后還可以跟一個(gè) finally塊,用于回收在try塊里打開的物理資源驱入,異常處理機(jī)制會(huì)保證 finally塊總被執(zhí)行赤炒。 而 throw用于拋出一個(gè)實(shí)際的異常, throw可以單獨(dú)作為語句使用亏较,拋出一個(gè)具體的異常對(duì)象 莺褒。
與 Java 的異常處理機(jī)制相比, Kotlin 拋棄了checked 異常雪情,相當(dāng)于所有異常都是 runtime 異常遵岩,這意味著開發(fā)者想捕獲異常就捕獲,不想捕獲異常也行,不需要使用 throws 關(guān)鍵字聲明拋出異常尘执。

異常處理機(jī)制

使用 try...catch 捕獲異常

Kotlin 的異常處理機(jī)制的語法結(jié)構(gòu)如下:

try{
//業(yè)務(wù)實(shí)現(xiàn)代碼
...
}catch(e:Exception){
//異常處理代碼
...
}
...
finally{
//可選的finally 塊
}

與Java的異常處理流程相同舍哄,整個(gè)異常處理流程可包含 1個(gè)try塊、0~N個(gè)catch塊誊锭、 0~1個(gè) finally塊表悬,但 catch塊與 finally塊至少出現(xiàn)其中之一。
如果在執(zhí)行try塊中的業(yè)務(wù)邏輯代碼時(shí)出現(xiàn)異常丧靡,系統(tǒng)將自動(dòng)生成一個(gè)異常對(duì)象蟆沫,該異常對(duì)象被提交給運(yùn)行時(shí)環(huán)境,這個(gè)過程被稱為拋出( throw)異常温治。
當(dāng)運(yùn)行時(shí)環(huán)境收到異常對(duì)象時(shí)饭庞,會(huì)尋找能處理該異常對(duì)象的 catch塊,如果找到了合適的catch塊熬荆,就把該異常對(duì)象交給該 catch 塊處理但绕,這個(gè)過程被稱為捕獲( catch)異常;如果運(yùn)行時(shí)環(huán)境找不到捕獲異常的catch塊,則運(yùn)行時(shí)環(huán)境中止惶看,程序也將退出 捏顺。

import java.io.FileInputStream
import java.io.IOException

fun main(args: Array<String>) {
    var fis:FileInputStream? = null
    try{
        fis = FileInputStream("a.txt")
        println(fis.read())
    }catch (e:IOException){
        println("讀取文件出現(xiàn)異常")
        //return 語句強(qiáng)制方法返回
        //return
        //使用 exit 退出虛擬機(jī)
        //System.exit(1)
    }finally {
        //關(guān)閉磁盤文件,回收資源
        fis?.close()
        println("執(zhí)行 finally 塊里的資源回收!")
    }
}

上面程序在try塊后增加了 finally 塊纬黎,用于回收在try塊中打開的物理資源 幅骄。 注意程序的 catch塊中有一條return語句,該語句強(qiáng)制方法返回本今。 在通常情況下拆座, 一旦在方法中執(zhí)行到return語句的地方, 程序?qū)⒘⒓唇Y(jié)束該方法; 而現(xiàn)在不會(huì)了冠息,雖然return語句也強(qiáng)制方法結(jié)束挪凑,但一定會(huì)先執(zhí)行 finally塊中的代碼。

在異常處理的 catch 塊中使用 System.exit(1)語句來退出虛擬機(jī)逛艰。運(yùn)行上面代碼躏碳,可以發(fā)現(xiàn)finally塊沒有被執(zhí)行。 如果在異常處理代碼中使用 System.exit(1)語 句來退出虛擬機(jī)散怖,則finally塊將失去執(zhí)行的機(jī)會(huì)菇绵。

當(dāng)程序執(zhí)行try塊、catch 塊時(shí)遇到了 return 或 throw 語句镇眷,這兩條語句都會(huì)導(dǎo)致該方法立即結(jié)束咬最, 但是系統(tǒng)執(zhí)行這兩條語句并不會(huì)結(jié)束該方法, 而是去尋找該異常處理流程中是否包含finally塊欠动,如果沒有finally塊永乌,程序?qū)⒘⒓磮?zhí)行return或 throw語句,方法中止;如果有finally塊,系統(tǒng)就立即開始執(zhí)行 finally 塊翅雏,只有當(dāng) finally 塊執(zhí)行完成后圈驼,系統(tǒng)才會(huì)再次跳回來執(zhí)行try塊、catch 塊中的 return 或 throw 語句 : 如果 finally塊中也使用了return 或 throw 等導(dǎo)致方法中止的語句枚荣, finally塊己經(jīng)中止了方法碗脊,系統(tǒng)將不會(huì)跳回去執(zhí)行try 塊、catch塊中的任何代碼橄妆。

異常類的繼承體系

與Java 的異常處理流程類似衙伶,當(dāng)運(yùn)行時(shí)環(huán)境接收到異常對(duì)象后,會(huì)依次判斷該異常對(duì)象是否是 catch 塊后異常類或其子類的實(shí)例害碾,如果是矢劲,運(yùn)行時(shí)環(huán)境將調(diào)用該 catch塊來處理該異常;否則將再次拿該異常對(duì)象和下一個(gè) catch塊中的異常類進(jìn)行比較。
當(dāng)程序進(jìn)入負(fù)責(zé)異常處理的 catch塊時(shí)慌随,系統(tǒng)生成的異常對(duì)象 ex 將會(huì)傳給 catch 塊后的異常形參芬沉,從而允許 catch 塊通過該對(duì)象來獲得異常的詳細(xì)信息 。

Kotlin 提供了 kotlin.Throwable 類阁猜,所有的異常類都是 Throwable 類的子類丸逸。此外,Kotlin 還通過類型別名的方式引入了 Java 的 Error和 Exception 兩個(gè)子類剃袍,但 Kotlin 并沒有嚴(yán)格區(qū)分錯(cuò)誤和異常(在 Java 中 Error 和 Exception 的區(qū)別也不明顯) 黄刚。 此外, Kotlin 完全借用了 Java 的異常體系民效,這些異常類之間有嚴(yán)格的繼承關(guān)系 憔维。
下面看 一個(gè)異常捕獲的例子:

fun main(args: Array<String>) {
    try {
        var a = Integer.parseInt(args[0])
        var b = Integer.parseInt(args[1])
        val c = a / b
        println(" 您輸入的兩個(gè)數(shù)相除的結(jié)果是 : ${c} ")
    } catch (ie: IndexOutOfBoundsException) {
        println(" 數(shù)組越界 : 運(yùn)行程序時(shí)輸入 的參數(shù)個(gè)數(shù)不夠 ")
    } catch (ne: NumberFormatException) {
        println(" 數(shù)字格式異常 : 程序只能接收整數(shù)參數(shù) ")
    } catch (ae: ArithmeticException) {
        println(" 算術(shù)異常 ")
    } catch (e: Exception) {
        println(" 未知異常 ")
    }
}

訪問異常信息

如果程序需要在 catch 塊中訪問異常對(duì)象的相關(guān)信息,則可以通過訪問 catch 塊后的異常形參來獲得畏邢。當(dāng)運(yùn)行時(shí)環(huán)境決定調(diào)用某個(gè) catch 塊來處理該異常對(duì)象時(shí)业扒,會(huì)將異常對(duì)象賦給catch塊后的異常參數(shù),程序即可通過該參數(shù)來獲得異常的相關(guān)信息 舒萎。
所有的異常對(duì)象都包含了如下幾個(gè)常用屬性和方法程储。

  • message: 該屬性返回該異常的詳細(xì)描述字符串。
  • stackTrace: 該屬性返回該異常的跟蹤棧信息逆甜。
  • printStackTrace(): 將該異常的跟蹤棧信息輸出到標(biāo)準(zhǔn)錯(cuò)誤輸出虱肄。
  • printStackTrace(PrintStream s): 將該異常的跟蹤棧信息輸出到指定輸出流。

try語句是表達(dá)式

與if語句類似交煞, Kotlin 的try語句也是表達(dá)式,因此位try語句也可用于對(duì)變量賦值斟或。 try表達(dá)式的返回值是try塊中的最后一個(gè)表達(dá)式的值素征,或者是被執(zhí)行的 catch 塊中的最后一個(gè)表達(dá)式的值, finally 塊中的內(nèi)容不會(huì)影響表達(dá)式的結(jié)果。
如下程序示范了try語句是一個(gè)表達(dá)式的效果御毅。

fun main(args: Array<String>) {
    val input = readLine()
    //用 try 表達(dá)式對(duì)變量 a 賦值
    val a:Int? = try{Integer.parseInt(input)}catch (e: NumberFormatException){null}finally {
        "sss"
    }

    println(a)
}

使用 throw拋出異常

與Java類似根欧,Kotlin也允許程序自行拋出異常,自行拋出異常使用 throw語句來完成端蛆。

拋出異常

如果需要在程序中自行拋出異常凤粗,則應(yīng)使用 throw 語句。throw 語句可以單獨(dú)使用今豆,throw 語句拋出的不是異常類嫌拣,而是一個(gè)異常實(shí)例,而且每次只能拋出一個(gè)異常實(shí)例呆躲。 throw語句的語法格式如下:

  • throw Exceptioninstance

由于 Kotlin 沒有 checked 異常(即使某個(gè)異常在 Java 中原本是 checked 異常异逐,在 Kotlin 中它也不是 checked 異常),因此 Kotlin 拋出異常的語句無須放在 try 塊中插掂,程序既可以顯式使用 try...catch 來捕獲井處理該異常灰瞻,也可以完全不理會(huì)該異常,把該異常交給該方法調(diào)用者處理辅甥。例如下面程序:

fun main(args: Array<String>) {
    //無論該異常在 Java 中是否為 checked 異常
    // 在 Kotlin 中該異常都不是 checked 異常
    throwChecked(-5)
    throwRuntime(4)
}

fun throwChecked(a:Int){
    if(a>0){
        //自行拋出普通異常酝润,在 Kotlin 中 也不 是 checked 異常
        //該代碼不必處于 try 塊中
        throw Exception("a的值大于 0,不符合要求")
    }
}

fun throwRuntime(a:Int){
    if(a>0){
        throw RuntimeException("a的值大于 0璃弄,不符合要求")
    }
}

上面代碼分別拋出了 Exception 和 RuntimeException 異常要销, Exception 在 Java 中就是checked 異常 , 但在 Kotlin 中不是谢揪,所以我們看到上面兩個(gè)方法對(duì)兩種不同異常的處理完全相同蕉陋。

自定義異常類

在通常情況下,程序很少會(huì)自行拋出系統(tǒng)異常拨扶,因?yàn)楫惓n惖念惷ǔR舶嗽摦惓5挠杏眯畔?凳鬓。所以在選擇拋出異常時(shí),應(yīng)該選擇合適的異常類患民,從而可以明確地描述該異常情況缩举。在這種情形下,應(yīng)用程序常常需要拋出自定義異常 匹颤。

用戶自定義異常都應(yīng)該繼承 Exception 基類仅孩,定義異常類時(shí)通常需要提供兩個(gè)構(gòu)造器: 一個(gè)是無參數(shù)的構(gòu)造器;另一個(gè)是帶一個(gè)字符串參數(shù)的構(gòu)造器,這個(gè)字符串將作為該異常對(duì)象的描述信息(也就是異常對(duì)象的message屬性的返回值) 印蓖。
下面例子程序創(chuàng)建了一個(gè)自定義異常類辽慕。

class AuctionException : Exception {
    //無參數(shù)的構(gòu)造器
    constructor() {

    }

    //帶一個(gè)字符串參數(shù)的構(gòu)造器
    constructor(msg: String) : super(msg) {


    }
}

上面程序創(chuàng)建了 AuctionException 異常類 , 井為該異常類提供了兩個(gè)構(gòu)造器 赦肃。 尤其是帶一個(gè)字符串參數(shù)的構(gòu)造器溅蛉,該構(gòu)造器通過 super 委托調(diào)用父類的構(gòu)造器公浪, 正是這個(gè)super調(diào)用可以將此字符串參數(shù)傳給異常對(duì)象的message屬性, 該 message屬性就是該異常對(duì)象的詳細(xì)描述信息 船侧。
在大部分情況下欠气,創(chuàng)建自定義異常都可采用與 AuctionException.kt相似的代碼完成,只需改變 AuctionException異常類的類名即可镜撩,讓該異常類的類名可以準(zhǔn)確描述該異常预柒。

catch 和 throw 同時(shí)使用

實(shí)際應(yīng)用的異常處理可能需要更復(fù)雜的處理方式,當(dāng)一個(gè)異常出現(xiàn)時(shí)袁梗,單靠某個(gè)方法無法完全處理該異常宜鸯,必須通過幾個(gè)方法協(xié)作才可完全處理該異常。也就是說围段,在異常出現(xiàn)的當(dāng)前方法中顾翼,程序只對(duì)異常進(jìn)行部分處理,還有些處理需要在該方法的調(diào)用者中才能完成 奈泪,所以應(yīng)該再次拋出異常适贸,讓該方法的調(diào)用者也能捕獲到異常。
為了實(shí)現(xiàn)這種通過多個(gè)方法協(xié)作處理同一個(gè)異常的情形涝桅,可以在 catch塊中結(jié)合 throw語句來完成拜姿。如下例子程序示范了這種 catch 和 throw 同時(shí)使用的方法。

class AuctionTest {
    var initPrice: Double = 30.0
    fun bid(bidPrice: String) {
        var d: Double =0.0
        try {
            bidPrice.toDouble()
        } catch (e: Exception) {
            //此處完成本方法中可以對(duì)異常執(zhí)行的修復(fù)處理
            //此處僅僅是在控制臺(tái)打印異常的跟蹤棧信息
            e.printStackTrace()
            //再次拋出自定義異常
            throw AuctionException("”競(jìng)拍價(jià)必須是數(shù)值冯遂,不能包含其他字符!”")
        }

        if (initPrice > d) {
            throw AuctionException("競(jìng)拍價(jià)比起拍價(jià)低蕊肥,不允許競(jìng)拍! ")

        }

        initPrice = d
    }
}

fun main(args: Array<String>) {
    val at = AuctionTest()
    try {
        at.bid("ed")
    } catch (ae: AuctionException) {
        //再次捕獲到 bid ()方法中的異常,并對(duì)該異常進(jìn)行處理
        println(ae.message)

    }
}

這種 catch 和 throw 結(jié)合使用的情況在大型企業(yè)級(jí)應(yīng)用中非常常用。企業(yè)級(jí)應(yīng)用對(duì)異常的處理通常分成兩個(gè)部分:1 后臺(tái)需要通過日志來記錄異常發(fā)生的詳細(xì)情況:2 應(yīng)用還需要根據(jù)異常向應(yīng)用使用者傳達(dá)某種提示蛤肌。在這種情形下壁却,所有異常都需要兩個(gè)方法共同完成,也就必須結(jié)合使用 catch和 throw裸准。

throw語句是表達(dá)式

與 try語句是表達(dá)式一樣展东, Kotlin 的throw語句也是表達(dá)式,但由于throw表達(dá)式的類型比較特殊炒俱,是 Nothing 類型盐肃,因此很少將 throw 語句賦值給其他變量,但我們可以在Elvis表達(dá)式中使用 throw 表達(dá)式权悟。例如如下代碼:

class User(var name:String? = null,var password:String? =null){

}

fun main(args: Array<String>) {
    val user =User()
    //在 Elvis 表達(dá)式中使用 throw 表達(dá)式
    //throw表達(dá)式表示程序出現(xiàn)異常砸王,不會(huì)真正對(duì)變量賦值
    val th :String = user.name ?: throw NullPointerException("”目標(biāo)對(duì)象不能為 null")
    println(th)
}

上面代碼將user.name賦值給th變量,由于user.name 是可空類型峦阁,因此程序?qū)?user.name使用了Elvis表達(dá)式進(jìn)行判斷:當(dāng) user.name不為null時(shí)谦铃,將其值賦給user.name; 否則使用 throw表達(dá)式的值 , throw表達(dá)式的類型是 Nothing榔昔, 用于表示程序無法“真正”得 到該表達(dá)式的值荷辕。因此凿跳,如果 user.name為 null件豌,程序?qū)?huì)出現(xiàn)異常疮方,不會(huì)對(duì) th變量賦值, 故可將 th變量聲明為String類型茧彤。
編譯骡显、運(yùn)行該程序,可看到程序因?yàn)?NullPointerException 異常而結(jié)束 曾掂。

Nothing 類型沒有值惫谤,而是用于標(biāo)記永遠(yuǎn)無法“真正”返回的表達(dá)式,因此程序不會(huì)獲取表達(dá)式的值 珠洗。 當(dāng)我們自己定義函數(shù)時(shí) 溜歪,也可使用 Nothing 來標(biāo)記一個(gè)永遠(yuǎn)不會(huì)返回的函數(shù)。

fun fail(message: String): Nothing {
    throw IllegalArgumentException(message)
}

異常的跟蹤棧

異常對(duì)象的printStackTrace()方法用于打印異常的跟蹤棧信息许蓖,根據(jù)printStackTrace()方法的輸出結(jié)果蝴猪,開發(fā)者可以找到異常的源頭,并跟蹤到異常一路觸發(fā)的過程:

class SelfException : Exception {
    constructor() {
    }

    constructor(msg: String) : super(msg) {
    }
}

class PrintStackTraceTest{
    fun firstMethod(){
        secondMethod()
    }
    fun secondMethod(){
        thirdMethod()
    }

    fun thirdMethod(){
       throw SelfException("自定義異常信息")
    }
}

fun main(args: Array<String>) {
    PrintStackTraceTest().firstMethod()
}

如圖:


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膊爪,一起剝皮案震驚了整個(gè)濱河市自阱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌米酬,老刑警劉巖沛豌,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赃额,居然都是意外死亡加派,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門跳芳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芍锦,“玉大人,你說我怎么就攤上這事筛严∽淼” “怎么了?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵桨啃,是天一觀的道長(zhǎng)车胡。 經(jīng)常有香客問我,道長(zhǎng)照瘾,這世上最難降的妖魔是什么匈棘? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮析命,結(jié)果婚禮上主卫,老公的妹妹穿的比我還像新娘逃默。我一直安慰自己,他們只是感情好簇搅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布完域。 她就那樣靜靜地躺著,像睡著了一般瘩将。 火紅的嫁衣襯著肌膚如雪吟税。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天姿现,我揣著相機(jī)與錄音肠仪,去河邊找鬼。 笑死备典,一個(gè)胖子當(dāng)著我的面吹牛异旧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播提佣,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吮蛹,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了镐依?” 一聲冷哼從身側(cè)響起匹涮,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎槐壳,沒想到半個(gè)月后然低,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡务唐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年雳攘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枫笛。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吨灭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出刑巧,到底是詐尸還是另有隱情喧兄,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布啊楚,位于F島的核電站吠冤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏恭理。R本人自食惡果不足惜拯辙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望颜价。 院中可真熱鬧涯保,春花似錦诉濒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撇他,卻和暖如春茄猫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背困肩。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脆侮,地道東北人锌畸。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像靖避,于是被迫代替她去往敵國和親潭枣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 異常分類 Java將異常分為兩種幻捏,Checked異常和Runtime異常盆犁。Java認(rèn)為Checked異常都是可以在...
    LLorenzo閱讀 710評(píng)論 0 1
  • 2.JAVA異常 異常指不期而至的各種狀況,如:文件找不到篡九、網(wǎng)絡(luò)連接失敗谐岁、非法參數(shù)等。異常是一個(gè)事件榛臼,它發(fā)生在程...
    青城樓主閱讀 555評(píng)論 0 0
  • Java異常類型 所有異常類型都是Throwable的子類伊佃,Throwable把異常分成兩個(gè)不同分支的子類Erro...
    予別她閱讀 926評(píng)論 0 2
  • 初識(shí)異常(Exception) 比如我們?cè)谌?shù)組里面的某個(gè)值得時(shí)候,經(jīng)常會(huì)出現(xiàn)定義的取值范圍超過了數(shù)組的大小沛善,那么...
    iDaniel閱讀 1,869評(píng)論 1 2
  • 記得在參加《人工智能》線下讀書會(huì)時(shí)航揉,多數(shù)書友都擔(dān)心人工智能對(duì)人類的威脅,斷言人類與人工智能之間必有一戰(zhàn)金刁。對(duì)此...
    大肚蕭寒閱讀 318評(píng)論 2 2