<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          教妹學(xué) Java 第 41 講:異常處理機(jī)制

          共 5935字,需瀏覽 12分鐘

           ·

          2021-07-04 15:00

          “二哥,今天就要學(xué)習(xí)異常了嗎?”三妹問(wèn)。

          “是的。只有正確地處理好異常,才能保證程序的可靠性,所以異常的學(xué)習(xí)還是很有必要的?!蔽艺f(shuō)。

          “那到底什么是異常呢?”三妹問(wèn)。

          “異常是指中斷程序正常執(zhí)行的一個(gè)不確定的事件。當(dāng)異常發(fā)生時(shí),程序的正常執(zhí)行流程就會(huì)被打斷。一般情況下,程序都會(huì)有很多條語(yǔ)句,如果沒(méi)有異常處理機(jī)制,前面的語(yǔ)句一旦出現(xiàn)了異常,后面的語(yǔ)句就沒(méi)辦法繼續(xù)執(zhí)行了?!?/p>

          “有了異常處理機(jī)制后,程序在發(fā)生異常的時(shí)候就不會(huì)中斷,我們可以對(duì)異常進(jìn)行捕獲,然后改變程序執(zhí)行的流程?!?/p>

          “除此之外,異常處理機(jī)制可以保證我們向用戶(hù)提供友好的提示信息,而不是程序原生的異常信息——用戶(hù)根本理解不了?!?/p>

          “不過(guò),站在開(kāi)發(fā)者的角度,我們更希望看到原生的異常信息,因?yàn)檫@有助于我們更快地找到 bug 的根源,反而被過(guò)度包裝的異常信息會(huì)干擾我們的視線?!?/p>

          “Java 語(yǔ)言在一開(kāi)始就提供了相對(duì)完善的異常處理機(jī)制,這種機(jī)制大大降低了編寫(xiě)可靠程序的門(mén)檻,這也是 Java 之所以能夠流行的原因之一?!?/p>

          “那導(dǎo)致程序拋出異常的原因有哪些呢?”三妹問(wèn)。

          比如說(shuō):

          • 程序在試圖打開(kāi)一個(gè)不存在的文件;
          • 程序遇到了網(wǎng)絡(luò)連接問(wèn)題;
          • 用戶(hù)輸入了糟糕的數(shù)據(jù);
          • 程序在處理算術(shù)問(wèn)題時(shí)沒(méi)有考慮除數(shù)為 0 的情況;

          等等等等。

          挑個(gè)最簡(jiǎn)單的原因來(lái)說(shuō)吧。

          public class Demo {
              public static void main(String[] args) {
                  System.out.println(10/0);
              }
          }

          這段代碼在運(yùn)行的時(shí)候拋出的異常信息如下所示:

          Exception in thread "main" java.lang.ArithmeticException: / by zero
           at com.itwanger.s41.Demo.main(Demo.java:8)

          “你看,三妹,這個(gè)原生的異常信息對(duì)用戶(hù)來(lái)說(shuō),顯然是不太容易理解的,但對(duì)于我們開(kāi)發(fā)者來(lái)說(shuō),簡(jiǎn)直不要太直白了——很容易就能定位到異常發(fā)生的根源。”

          “哦,我知道了。下一個(gè)問(wèn)題,我經(jīng)??吹揭恍┪恼吕锾岬?Exception 和 Error,二哥你能幫我解釋一下它們之間的區(qū)別嗎?”三妹問(wèn)。

          “這是一個(gè)好問(wèn)題呀,三妹!”

          從單詞的釋義上來(lái)看,error 為錯(cuò)誤,exception 為異常,錯(cuò)誤的等級(jí)明顯比異常要高一些。

          從程序的角度來(lái)看,也的確如此。

          Error 的出現(xiàn),意味著程序出現(xiàn)了嚴(yán)重的問(wèn)題,而這些問(wèn)題不應(yīng)該再交給 Java 的異常處理機(jī)制來(lái)處理,程序應(yīng)該直接崩潰掉,比如說(shuō) OutOfMemoryError,內(nèi)存溢出了,這就意味著程序在運(yùn)行時(shí)申請(qǐng)的內(nèi)存大于系統(tǒng)能夠提供的內(nèi)存,導(dǎo)致出現(xiàn)的錯(cuò)誤,這種錯(cuò)誤的出現(xiàn),對(duì)于程序來(lái)說(shuō)是致命的。

          Exception 的出現(xiàn),意味著程序出現(xiàn)了一些在可控范圍內(nèi)的問(wèn)題,我們應(yīng)當(dāng)采取措施進(jìn)行挽救。

          比如說(shuō)之前提到的 ArithmeticException,很明顯是因?yàn)槌龜?shù)出現(xiàn)了 0 的情況,我們可以選擇捕獲異常,然后提示用戶(hù)不應(yīng)該進(jìn)行除 0 操作,當(dāng)然了,更好的做法是直接對(duì)除數(shù)進(jìn)行判斷,如果是 0 就不進(jìn)行除法運(yùn)算,而是告訴用戶(hù)換一個(gè)非 0 的數(shù)進(jìn)行運(yùn)算。

          “三妹,還能想到其他的問(wèn)題嗎?”

          “嗯,不用想,二哥,我已經(jīng)提前做好預(yù)習(xí)工作了。”三妹自信地說(shuō),“異常又可以分為 checked 和 unchecked,它們之間又有什么區(qū)別呢?”

          “哇,三妹,果然又是一個(gè)好問(wèn)題呢?!?/p>

          checked 異常(檢查型異常)在源代碼里必須顯式地捕獲或者拋出,否則編譯器會(huì)提示你進(jìn)行相應(yīng)的操作;而 unchecked 異常(非檢查型異常)就是所謂的運(yùn)行時(shí)異常,通常是可以通過(guò)編碼進(jìn)行規(guī)避的,并不需要顯式地捕獲或者拋出。

          “我先畫(huà)一幅思維導(dǎo)圖給你感受一下?!?/p>

          首先,Exception 和 Error 都繼承了 Throwable 類(lèi)。換句話說(shuō),只有 Throwable 類(lèi)(或者子類(lèi))的對(duì)象才能使用 throw 關(guān)鍵字拋出,或者作為 catch 的參數(shù)類(lèi)型。

          面試中經(jīng)常問(wèn)到的一個(gè)問(wèn)題是,NoClassDefFoundError 和 ClassNotFoundException 有什么區(qū)別?

          “三妹你知道嗎?”

          “不知道,二哥,你解釋下唄?!?/p>

          它們都是由于系統(tǒng)運(yùn)行時(shí)找不到要加載的類(lèi)導(dǎo)致的,但是觸發(fā)的原因不一樣。

          • NoClassDefFoundError:程序在編譯時(shí)可以找到所依賴(lài)的類(lèi),但是在運(yùn)行時(shí)找不到指定的類(lèi)文件,導(dǎo)致拋出該錯(cuò)誤;原因可能是 jar 包缺失或者調(diào)用了初始化失敗的類(lèi)。
          • ClassNotFoundException:當(dāng)動(dòng)態(tài)加載 Class 對(duì)象的時(shí)候找不到對(duì)應(yīng)的類(lèi)時(shí)拋出該異常;原因可能是要加載的類(lèi)不存在或者類(lèi)名寫(xiě)錯(cuò)了。

          其次,像 IOException、ClassNotFoundException、SQLException 都屬于 checked 異常;像 RuntimeException 以及子類(lèi) ArithmeticException、ClassCastException、ArrayIndexOutOfBoundsException、NullPointerException,都屬于 unchecked 異常。

          unchecked 異??梢圆辉诔绦蛑酗@示處理,就像之前提到的 ArithmeticException 就是的;但 checked 異常必須顯式處理。

          比如說(shuō)下面這行代碼:

          Class clz = Class.forName("com.itwanger.s41.Demo1");

          如果沒(méi)做處理,比如說(shuō)在 Intellij IDEA 環(huán)境下,就會(huì)提示你這行代碼可能會(huì)拋出 java.lang.ClassNotFoundException。

          建議你要么使用 try-catch 進(jìn)行捕獲:

          try {
              Class clz = Class.forName("com.itwanger.s41.Demo1");
          catch (ClassNotFoundException e) {
              e.printStackTrace();
          }

          注意打印異常堆棧信息的 printStackTrace() 方法,該方法會(huì)將異常的堆棧信息打印到標(biāo)準(zhǔn)的控制臺(tái)下,如果是測(cè)試環(huán)境,這樣的寫(xiě)法還 OK,如果是生產(chǎn)環(huán)境,這樣的寫(xiě)法是不可取的,必須使用日志框架把異常的堆棧信息輸出到日志系統(tǒng)中,否則可能沒(méi)辦法跟蹤。

          要么在方法簽名上使用 throws 關(guān)鍵字拋出:

          public class Demo1 {
              public static void main(String[] args) throws ClassNotFoundException {
                  Class clz = Class.forName("com.itwanger.s41.Demo1");
              }
          }

          這樣做的好處是不需要對(duì)異常進(jìn)行捕獲處理,只需要交給 Java 虛擬機(jī)來(lái)處理即可;壞處就是沒(méi)法針對(duì)這種情況做相應(yīng)的處理。

          “二哥,針對(duì) checked 異常,我在知乎上看到一個(gè)帖子,說(shuō) Java 中的 checked 很沒(méi)有必要,這種異常在編譯期要么 try-catch,要么 throws,但又不一定會(huì)出現(xiàn)異常,你覺(jué)得這樣的設(shè)計(jì)有意義嗎?”三妹提出了一個(gè)很尖銳的問(wèn)題。

          “哇,這種問(wèn)題問(wèn)的好?!蔽也挥傻脤?duì)三妹心生敬佩。

          “的確,checked 異常在業(yè)界是有爭(zhēng)論的,它假設(shè)我們捕獲了異常,并且針對(duì)這種情況作了相應(yīng)的處理,但有些時(shí)候,根本就沒(méi)法處理?!蔽艺f(shuō),“就拿上面提到的 ClassNotFoundException 異常來(lái)說(shuō),我們假設(shè)對(duì)其進(jìn)行了 try-catch,可真的出現(xiàn)了 ClassNotFoundException 異常后,我們也沒(méi)多少的可操作性,再 Class.forName() 一次?”

          另外,checked 異常也不兼容函數(shù)式編程,后面如果你寫(xiě) Lambda/Stream 代碼的時(shí)候,就會(huì)體驗(yàn)到這種苦澀。

          當(dāng)然了,checked 異常并不是一無(wú)是處,尤其是在遇到 IO 或者網(wǎng)絡(luò)異常的時(shí)候,比如說(shuō)進(jìn)行 Socket 鏈接,我大致寫(xiě)了一段:

          public class Demo2 {
              private String mHost;
              private int mPort;
              private Socket mSocket;
              private final Object mLock = new Object();

              public void run() {
              }

              private void initSocket() {
                  while (true) {
                      try {
                          Socket socket = new Socket(mHost, mPort);
                          synchronized (mLock) {
                              mSocket = socket;
                          }
                          break;
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }

          當(dāng)發(fā)生 IOException 的時(shí)候,socket 就重新嘗試連接,否則就 break 跳出循環(huán)。意味著如果 IOException 不是 checked 異常,這種寫(xiě)法就略顯突兀,因?yàn)?IOException 沒(méi)辦法像 ArithmeticException 那樣用一個(gè) if 語(yǔ)句判斷除數(shù)是否為 0 去規(guī)避。

          或者說(shuō),強(qiáng)制性的 checked 異常可以讓我們?cè)诰幊痰臅r(shí)候去思考,遇到這種異常的時(shí)候該怎么更優(yōu)雅的去處理。顯然,Socket 編程中,肯定是會(huì)遇到 IOException 的,假如 IOException 是非檢查型異常,就意味著開(kāi)發(fā)者也可以不考慮,直接跳過(guò),交給 Java 虛擬機(jī)來(lái)處理,但我覺(jué)得這樣做肯定更不合適。

          “好了,三妹,關(guān)于異常處理機(jī)制這節(jié)就先講到這里吧。”我松了一口氣,對(duì)三妹說(shuō)。

          “好的,二哥,你去休息吧?!?/p>

          “對(duì)了,三妹,我定個(gè)姑婆婆的外賣(mài)吧,晚上我們喝粥?!?/p>

          “好呀,我要兩個(gè)豆沙包?!?/p>


          PS:點(diǎn)擊「閱讀原文」可直達(dá)《教妹學(xué)Java》專(zhuān)欄的 GitHub 開(kāi)源地址,記得 star 哦!

          瀏覽 40
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩av在线小说 日韩av在线直播 | 欧美系列-熊猫成人网 | 久久精品国产亚洲AV成人婷婷 | 老外玩csgo中国的妹子视频 | 日日躁夜夜躁夜夜揉人人视频 |