<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>

          Java異常詳解及如何處理

          共 18685字,需瀏覽 38分鐘

           ·

          2022-07-10 17:51

          作者:lulipro
          來(lái)源:www.cnblogs.com/lulipro

          簡(jiǎn)介

          程序運(yùn)行時(shí),發(fā)生的不被期望的事件,它阻止了程序按照程序員的預(yù)期正常執(zhí)行,這就是異常。異常發(fā)生時(shí),是任程序自生自滅,立刻退出終止,還是輸出錯(cuò)誤給用戶?或者用C語(yǔ)言風(fēng)格:用函數(shù)返回值作為執(zhí)行狀態(tài)?。

          Java提供了更加優(yōu)秀的解決辦法:異常處理機(jī)制。

          異常處理機(jī)制能讓程序在異常發(fā)生時(shí),按照代碼的預(yù)先設(shè)定的異常處理邏輯,針對(duì)性地處理異常,讓程序盡最大可能恢復(fù)正常并繼續(xù)執(zhí)行,且保持代碼的清晰。
          Java中的異??梢允呛瘮?shù)中的語(yǔ)句執(zhí)行時(shí)引發(fā)的,也可以是程序員通過(guò)throw 語(yǔ)句手動(dòng)拋出的,只要在Java程序中產(chǎn)生了異常,就會(huì)用一個(gè)對(duì)應(yīng)類型的異常對(duì)象來(lái)封裝異常,JRE就會(huì)試圖尋找異常處理程序來(lái)處理異常。

          Throwable類是Java異常類型的頂層父類,一個(gè)對(duì)象只有是 Throwable 類的(直接或者間接)實(shí)例,他才是一個(gè)異常對(duì)象,才能被異常處理機(jī)制識(shí)別。JDK中內(nèi)建了一些常用的異常類,我們也可以自定義異常。

          Java異常的分類和類結(jié)構(gòu)圖

          Java標(biāo)準(zhǔn)褲內(nèi)建了一些通用的異常,這些類以Throwable為頂層父類。

          Throwable又派生出Error類和Exception類。

          錯(cuò)誤:Error類以及他的子類的實(shí)例,代表了JVM本身的錯(cuò)誤。錯(cuò)誤不能被程序員通過(guò)代碼處理,Error很少出現(xiàn)。因此,程序員應(yīng)該關(guān)注Exception為父類的分支下的各種異常類。

          異常:Exception以及他的子類,代表程序運(yùn)行時(shí)發(fā)送的各種不期望發(fā)生的事件。可以被Java異常處理機(jī)制使用,是異常處理的核心。


          總體上我們根據(jù)Javac對(duì)異常的處理要求,將異常類分為2類。

          非檢查異常:

          Error 和 RuntimeException 以及他們的子類。javac在編譯時(shí),不會(huì)提示和發(fā)現(xiàn)這樣的異常,不要求在程序處理這些異常。所以如果愿意,我們可以編寫(xiě)代碼處理(使用try…catch…finally)這樣的異常,也可以不處理。對(duì)于這些異常,我們應(yīng)該修正代碼,而不是去通過(guò)異常處理器處理 。這樣的異常發(fā)生的原因多半是代碼寫(xiě)的有問(wèn)題。如除0錯(cuò)誤ArithmeticException,錯(cuò)誤的強(qiáng)制類型轉(zhuǎn)換錯(cuò)誤ClassCastException,數(shù)組索引越界ArrayIndexOutOfBoundsException,使用了空對(duì)象NullPointerException等等。

          檢查異常:

          除了Error 和 RuntimeException的其它異常。javac強(qiáng)制要求程序員為這樣的異常做預(yù)備處理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch語(yǔ)句捕獲它并處理,要么用throws子句聲明拋出它,否則編譯不會(huì)通過(guò)。這樣的異常一般是由程序的運(yùn)行環(huán)境導(dǎo)致的。因?yàn)槌绦蚩赡鼙贿\(yùn)行在各種未知的環(huán)境下,而程序員無(wú)法干預(yù)用戶如何使用他編寫(xiě)的程序,于是程序員就應(yīng)該為這樣的異常時(shí)刻準(zhǔn)備著。如SQLException , IOException,ClassNotFoundException 等。

          需要明確的是:檢查和非檢查是對(duì)于javac來(lái)說(shuō)的,這樣就很好理解和區(qū)分了。

          初識(shí)異常

          下面的代碼會(huì)演示2個(gè)異常類型:ArithmeticException 和 InputMismatchException。前者由于整數(shù)除0引發(fā),后者是輸入的數(shù)據(jù)不能被轉(zhuǎn)換為int類型引發(fā)。

          package com.example;
          import java. util .Scanner ;
          public class AllDemo
          {
               public static void main (String [] args )
               
          {
                     System . out. println( "----歡迎使用命令行除法計(jì)算器----" ) ;
                     CMDCalculate ();
               }
               public static void CMDCalculate ()
               
          {
                     Scanner scan = new Scanner ( System. in );
                     int num1 = scan .nextInt () ;
                     int num2 = scan .nextInt () ;
                     int result = devide (num1 , num2 ) ;
                     System . out. println( "result:" + result) ;
                     scan .close () ;
               }
               public static int devide (int num1, int num2 ){
                     return num1 / num2 ;
               }
          }
          /*****************************************
          ----歡迎使用命令行除法計(jì)算器----
          0
          Exception in thread "main" java.lang.ArithmeticException : / by zero
              at com.example.AllDemo.devide( AllDemo.java:30 )
              at com.example.AllDemo.CMDCalculate( AllDemo.java:22 )
              at com.example.AllDemo.main( AllDemo.java:12 )
          ----歡迎使用命令行除法計(jì)算器----
          r
          Exception in thread "main" java.util.InputMismatchException
              at java.util.Scanner.throwFor( Scanner.java:864 )
              at java.util.Scanner.next( Scanner.java:1485 )
              at java.util.Scanner.nextInt( Scanner.java:2117 )
              at java.util.Scanner.nextInt( Scanner.java:2076 )
              at com.example.AllDemo.CMDCalculate( AllDemo.java:20 )
              at com.example.AllDemo.main( AllDemo.java:12 )
          *****************************************/

          異常是在執(zhí)行某個(gè)函數(shù)時(shí)引發(fā)的,而函數(shù)又是層級(jí)調(diào)用,形成調(diào)用棧的,因?yàn)椋灰粋€(gè)函數(shù)發(fā)生了異常,那么他的所有的caller都會(huì)被異常影響。當(dāng)這些被影響的函數(shù)以異常信息輸出時(shí),就形成的了異常追蹤棧。

          異常最先發(fā)生的地方,叫做異常拋出點(diǎn)。


          從上面的例子可以看出,當(dāng)devide函數(shù)發(fā)生除0異常時(shí),devide函數(shù)將拋出ArithmeticException異常,因此調(diào)用他的CMDCalculate函數(shù)也無(wú)法正常完成,因此也發(fā)送異常,而CMDCalculate的caller——main 因?yàn)镃MDCalculate拋出異常,也發(fā)生了異常,這樣一直向調(diào)用棧的棧底回溯。這種行為叫做異常的冒泡,異常的冒泡是為了在當(dāng)前發(fā)生異常的函數(shù)或者這個(gè)函數(shù)的caller中找到最近的異常處理程序。由于這個(gè)例子中沒(méi)有使用任何異常處理機(jī)制,因此異常最終由main函數(shù)拋給JRE,導(dǎo)致程序終止。


          上面的代碼不使用異常處理機(jī)制,也可以順利編譯,因?yàn)?個(gè)異常都是非檢查異常。但是下面的例子就必須使用異常處理機(jī)制,因?yàn)楫惓J菣z查異常。

          代碼中我選擇使用throws聲明異常,讓函數(shù)的調(diào)用者去處理可能發(fā)生的異常。但是為什么只throws了IOException呢?因?yàn)镕ileNotFoundException是IOException的子類,在處理范圍內(nèi)。

          @Test
          public void testException() throws IOException
          {
             //FileInputStream的構(gòu)造函數(shù)會(huì)拋出FileNotFoundException
             FileInputStream fileIn = new FileInputStream("E:\\a.txt");
             int word;
             //read方法會(huì)拋出IOException
             while((word =  fileIn.read())!=-1)
             {
                 System.out.print((char)word);
             }
             //close方法會(huì)拋出IOException
             fileIn.clos
          }

          異常處理的基本語(yǔ)法

          在編寫(xiě)代碼處理異常時(shí),對(duì)于檢查異常,有2種不同的處理方式:使用try…catch…finally語(yǔ)句塊處理它?;蛘?,在函數(shù)簽名中使用throws 聲明交給函數(shù)調(diào)用者caller去解決。

          try…catch…finally語(yǔ)句塊

          try{
              //try塊中放可能發(fā)生異常的代碼。
              //如果執(zhí)行完try且不發(fā)生異常,則接著去執(zhí)行finally塊和finally后面的代碼(如果有的話)。
              //如果發(fā)生異常,則嘗試去匹配catch塊。
          }catch(SQLException SQLexception){
             //每一個(gè)catch塊用于捕獲并處理一個(gè)特定的異常,或者這異常類型的子類。Java7中可以將多個(gè)異常聲明在一個(gè)catch中。
             //catch后面的括號(hào)定義了異常類型和異常參數(shù)。如果異常與之匹配且是最先匹配到的,則虛擬機(jī)將使用這個(gè)catch塊來(lái)處理異常。
             //catch塊中可以使用這個(gè)塊的異常參數(shù)來(lái)獲取異常的相關(guān)信息。異常參數(shù)是這個(gè)catch塊中的局部變量,其它塊不能訪問(wèn)。
             //如果當(dāng)前try塊中發(fā)生的異常在后續(xù)的所有catch中都沒(méi)捕獲到,則先去執(zhí)行finally,然后到這個(gè)函數(shù)的外部caller中去匹配異常處理器。
             //如果try中沒(méi)有發(fā)生異常,則所有的catch塊將被忽略。
          }catch(Exception exception){
             //...
          }finally{
             //finally塊通常是可選的。
            //無(wú)論異常是否發(fā)生,異常是否匹配被處理,finally都會(huì)執(zhí)行。
            //一個(gè)try至少要有一個(gè)catch塊,否則, 至少要有1個(gè)finally塊。但是finally不是用來(lái)處理異常的,finally不會(huì)捕獲異常。
           //finally主要做一些清理工作,如流的關(guān)閉,數(shù)據(jù)庫(kù)連接的關(guān)閉等。
          }

          需要注意的地方

          1、try塊中的局部變量和catch塊中的局部變量(包括異常變量),以及finally中的局部變量,他們之間不可共享使用。

          2、每一個(gè)catch塊用于處理一個(gè)異常。異常匹配是按照catch塊的順序從上往下尋找的,只有第一個(gè)匹配的catch會(huì)得到執(zhí)行。匹配時(shí),不僅運(yùn)行精確匹配,也支持父類匹配,因此,如果同一個(gè)try塊下的多個(gè)catch異常類型有父子關(guān)系,應(yīng)該將子類異常放在前面,父類異常放在后面,這樣保證每個(gè)catch塊都有存在的意義。

          3、java中,異常處理的任務(wù)就是將執(zhí)行控制流從異常發(fā)生的地方轉(zhuǎn)移到能夠處理這種異常的地方去。也就是說(shuō):當(dāng)一個(gè)函數(shù)的某條語(yǔ)句發(fā)生異常時(shí),這條語(yǔ)句的后面的語(yǔ)句不會(huì)再執(zhí)行,它失去了焦點(diǎn)。執(zhí)行流跳轉(zhuǎn)到最近的匹配的異常處理catch代碼塊去執(zhí)行,異常被處理完后,執(zhí)行流會(huì)接著在“處理了這個(gè)異常的catch代碼塊”后面接著執(zhí)行。

          有的編程語(yǔ)言當(dāng)異常被處理后,控制流會(huì)恢復(fù)到異常拋出點(diǎn)接著執(zhí)行,這種策略叫做:resumption model of exception handling(恢復(fù)式異常處理模式 )

          而Java則是讓執(zhí)行流恢復(fù)到處理了異常的catch塊后接著執(zhí)行,這種策略叫做:termination model of exception handling(終結(jié)式異常處理模式)

          public static void main(String[] args){
                 try {
                     foo();
                 }catch(ArithmeticException ae) {
                     System.out.println("處理異常");
                 }
          }
          public static void foo(){
                 int a = 5/0;  //異常拋出點(diǎn)
                 System.out.println("為什么還不給我漲工資!!!");  //////////////////////不會(huì)執(zhí)行
          }

          throws 函數(shù)聲明

          throws聲明:如果一個(gè)方法內(nèi)部的代碼會(huì)拋出檢查異常(checked exception),而方法自己又沒(méi)有完全處理掉,則javac保證你必須在方法的簽名上使用throws關(guān)鍵字聲明這些可能拋出的異常,否則編譯不通過(guò)。

          throws是另一種處理異常的方式,它不同于try…catch…finally,throws僅僅是將函數(shù)中可能出現(xiàn)的異常向調(diào)用者聲明,而自己則不具體處理。

          采取這種異常處理的原因可能是:方法本身不知道如何處理這樣的異常,或者說(shuō)讓調(diào)用者處理更好,調(diào)用者需要為可能發(fā)生的異常負(fù)責(zé)。

          public void foo() throws ExceptionType1 , ExceptionType2 ,ExceptionTypeN
          {
              //foo內(nèi)部可以拋出 ExceptionType1 , ExceptionType2 ,ExceptionTypeN 類的異常,或者他們的子類的異常對(duì)象。
          }

          finally塊

          finally塊不管異常是否發(fā)生,只要對(duì)應(yīng)的try執(zhí)行了,則它一定也執(zhí)行。只有一種方法讓finally塊不執(zhí)行:System.exit()。因此finally塊通常用來(lái)做資源釋放操作:關(guān)閉文件,關(guān)閉數(shù)據(jù)庫(kù)連接等等。

          良好的編程習(xí)慣是:在try塊中打開(kāi)資源,在finally塊中清理釋放這些資源。

          需要注意的地方:

          1、finally塊沒(méi)有處理異常的能力。處理異常的只能是catch塊。

          2、在同一try…catch…finally塊中 ,如果try中拋出異常,且有匹配的catch塊,則先執(zhí)行catch塊,再執(zhí)行finally塊。如果沒(méi)有catch塊匹配,則先執(zhí)行finally,然后去外面的調(diào)用者中尋找合適的catch塊。

          3、在同一try…catch…finally塊中 ,try發(fā)生異常,且匹配的catch塊中處理異常時(shí)也拋出異常,那么后面的finally也會(huì)執(zhí)行:首先執(zhí)行finally塊,然后去外圍調(diào)用者中尋找合適的catch塊。

          throw 異常拋出語(yǔ)句

          throw exceptionObject

          程序員也可以通過(guò)throw語(yǔ)句手動(dòng)顯式的拋出一個(gè)異常。throw語(yǔ)句的后面必須是一個(gè)異常對(duì)象。

          throw 語(yǔ)句必須寫(xiě)在函數(shù)中,執(zhí)行throw 語(yǔ)句的地方就是一個(gè)異常拋出點(diǎn),它和由JRE自動(dòng)形成的異常拋出點(diǎn)沒(méi)有任何差別。

          public void save(User user)
          {
               if(user  == null)
                   throw new IllegalArgumentException("User對(duì)象為空");
               //......
          }

          異常的鏈化

          在一些大型的,模塊化的軟件開(kāi)發(fā)中,一旦一個(gè)地方發(fā)生異常,則如骨牌效應(yīng)一樣,將導(dǎo)致一連串的異常。假設(shè)B模塊完成自己的邏輯需要調(diào)用A模塊的方法,如果A模塊發(fā)生異常,則B也將不能完成而發(fā)生異常,但是B在拋出異常時(shí),會(huì)將A的異常信息掩蓋掉,這將使得異常的根源信息丟失。異常的鏈化可以將多個(gè)模塊的異常串聯(lián)起來(lái),使得異常信息不會(huì)丟失。

          異常鏈化:以一個(gè)異常對(duì)象為參數(shù)構(gòu)造新的異常對(duì)象。新的異對(duì)象將包含先前異常的信息。這項(xiàng)技術(shù)主要是異常類的一個(gè)帶Throwable參數(shù)的函數(shù)來(lái)實(shí)現(xiàn)的。這個(gè)當(dāng)做參數(shù)的異常,我們叫他根源異常(cause)。

          查看Throwable類源碼,可以發(fā)現(xiàn)里面有一個(gè)Throwable字段cause,就是它保存了構(gòu)造時(shí)傳遞的根源異常參數(shù)。這種設(shè)計(jì)和鏈表的結(jié)點(diǎn)類設(shè)計(jì)如出一轍,因此形成鏈也是自然的了。

          public class Throwable implements Serializable {
             private Throwable cause = this;
             public Throwable(String message, Throwable cause) {
                 fillInStackTrace();
                 detailMessage = message;
                 this.cause = cause;
             }
              public Throwable(Throwable cause) {
                 fillInStackTrace();
                 detailMessage = (cause==null ? null : cause.toString());
                 this.cause = cause;
             }
             //........
          }

          下面是一個(gè)例子,演示了異常的鏈化:從命令行輸入2個(gè)int,將他們相加,輸出。輸入的數(shù)不是int,則導(dǎo)致getInputNumbers異常,從而導(dǎo)致add函數(shù)異常,則可以在add函數(shù)中拋出

          一個(gè)鏈化的異常。

          public static void main(String[] args)
          {
             System.out.println("請(qǐng)輸入2個(gè)加數(shù)");
             int result;
             try
             {
                 result = add();
                 System.out.println("結(jié)果:"+result);
             } catch (Exception e){
                 e.printStackTrace();
             }
          }
          //獲取輸入的2個(gè)整數(shù)返回
          private static List<Integer> getInputNumbers()
          {
             List<Integer> nums = new ArrayList<>();
             Scanner scan = new Scanner(System.in);
             try {
                 int num1 = scan.nextInt();
                 int num2 = scan.nextInt();
                 nums.add(new Integer(num1));
                 nums.add(new Integer(num2));
             }catch(InputMismatchException immExp){
                 throw immExp;
             }finally {
                 scan.close();
             }
             return nums;
          }
          //執(zhí)行加法計(jì)算
          private static int add() throws Exception
          {
             int result;
             try {
                 List<Integer> nums =getInputNumbers();
                 result = nums.get(0)  + nums.get(1);
             }catch(InputMismatchException immExp){
                 throw new Exception("計(jì)算失敗",immExp);  /////////////////////////////鏈化:以一個(gè)異常對(duì)象為參數(shù)構(gòu)造新的異常對(duì)象。
             }
             return  result;
          }
          /*
          請(qǐng)輸入2個(gè)加數(shù)
          r 1
          java.lang.Exception: 計(jì)算失敗
             at practise.ExceptionTest.add(ExceptionTest.java:53)
             at practise.ExceptionTest.main(ExceptionTest.java:18)
          Caused by: java.util.InputMismatchException
             at java.util.Scanner.throwFor(Scanner.java:864)
             at java.util.Scanner.next(Scanner.java:1485)
             at java.util.Scanner.nextInt(Scanner.java:2117)
             at java.util.Scanner.nextInt(Scanner.java:2076)
             at practise.ExceptionTest.getInputNumbers(ExceptionTest.java:30)
             at practise.ExceptionTest.add(ExceptionTest.java:48)
             ... 1 more
          */

          自定義異常

          如果要自定義異常類,則擴(kuò)展Exception類即可,因此這樣的自定義異常都屬于檢查異常(checked exception)。如果要自定義非檢查異常,則擴(kuò)展自RuntimeException。

          按照國(guó)際慣例,自定義的異常應(yīng)該總是包含如下的構(gòu)造函數(shù):

          • 一個(gè)無(wú)參構(gòu)造函數(shù)

          • 一個(gè)帶有String參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。

          • 一個(gè)帶有String參數(shù)和Throwable參數(shù),并都傳遞給父類構(gòu)造函數(shù)

          • 一個(gè)帶有Throwable 參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。

          下面是IOException類的完整源代碼,可以借鑒。

          public class IOException extends Exception
          {
             static final long serialVersionUID = 7818375828146090155L;
             public IOException()
             
          {
                 super();
             }
             public IOException(String message)
             
          {
                 super(message);
             }
             public IOException(String message, Throwable cause)
             
          {
                 super(message, cause);
             }
             public IOException(Throwable cause)
             
          {
                 super(cause);
             }
          }

          異常的注意事項(xiàng)

          1、當(dāng)子類重寫(xiě)父類的帶有 throws聲明的函數(shù)時(shí),其throws聲明的異常必須在父類異常的可控范圍內(nèi)——用于處理父類的throws方法的異常處理器,必須也適用于子類的這個(gè)帶throws方法 。這是為了支持多態(tài)。

          例如,父類方法throws 的是2個(gè)異常,子類就不能throws 3個(gè)及以上的異常。父類throws IOException,子類就必須throws IOException或者IOException的子類。

          至于為什么?我想,也許下面的例子可以說(shuō)明。

          class Father
          {
             public void start() throws IOException
             
          {
                 throw new IOException();
             }
          }
          class Son extends Father
          {
             public void start() throws Exception
             
          {
                 throw new SQLException();
             }
          }
          /**********************假設(shè)上面的代碼是允許的(實(shí)質(zhì)是錯(cuò)誤的)***********************/
          class Test
          {
             public static void main(String[] args)
             
          {
                 Father[] objs = new Father[2];
                 objs[0] = new Father();
                 objs[1] = new Son();
                 for(Father obj:objs)
                 {
                 //因?yàn)镾on類拋出的實(shí)質(zhì)是SQLException,而IOException無(wú)法處理它。
                 //那么這里的try。。catch就不能處理Son中的異常。
                 //多態(tài)就不能實(shí)現(xiàn)了。
                     try {
                          obj.start();
                     }catch(IOException)
                     {
                          //處理IOException
                     }
                  }
            }
          }

          2、Java程序可以是多線程的。每一個(gè)線程都是一個(gè)獨(dú)立的執(zhí)行流,獨(dú)立的函數(shù)調(diào)用棧。如果程序只有一個(gè)線程,那么沒(méi)有被任何代碼處理的異常 會(huì)導(dǎo)致程序終止。如果是多線程的,那么沒(méi)有被任何代碼處理的異常僅僅會(huì)導(dǎo)致異常所在的線程結(jié)束。

          也就是說(shuō),Java中的異常是線程獨(dú)立的,線程的問(wèn)題應(yīng)該由線程自己來(lái)解決,而不要委托到外部,也不會(huì)直接影響到其它線程的執(zhí)行。

          finally塊和return

          public static void main(String[] args)
          {
             int re = bar();
             System.out.println(re);
          }
          private static int bar()
          {
             try{
                 return 5;
             } finally{
                 System.out.println("finally");
             }
          }
          /*輸出:
          finally
          */

          很多人面對(duì)這個(gè)問(wèn)題時(shí),總是在歸納執(zhí)行的順序和規(guī)律,不過(guò)我覺(jué)得還是很難理解。我自己總結(jié)了一個(gè)方法。用如下GIF圖說(shuō)明。


          也就是說(shuō):try…catch…finally中的return 只要能執(zhí)行,就都執(zhí)行了,他們共同向同一個(gè)內(nèi)存地址(假設(shè)地址是0x80)寫(xiě)入返回值,后執(zhí)行的將覆蓋先執(zhí)行的數(shù)據(jù),而真正被調(diào)用者取的返回值就是最后一次寫(xiě)入的。那么,按照這個(gè)思想,下面的這個(gè)例子也就不難理解了。


          finally中的return 會(huì)覆蓋 try 或者catch中的返回值。

          public static void main(String[] args)
             
          {
                 int result;
                 result  =  foo();
                 System.out.println(result);     /////////2
                 result = bar();
                 System.out.println(result);    /////////2
             }
             @SuppressWarnings("finally")
             public static int foo()
             
          {
                 trz{
                     int a = 5 / 0;
                 } catch (Exception e){
                     return 1;
                 } finally{
                     return 2;
                 }
             }
             @SuppressWarnings("finally")
             public static int bar()
             
          {
                 try {
                     return 1;
                 }finally {
                     return 2;
                 }
             }

          finally中的return會(huì)抑制(消滅)前面try或者catch塊中的異常

          class TestException
          {
             public static void main(String[] args)
             
          {
                 int result;
                 try{
                     result = foo();
                     System.out.println(result);           //輸出100
                 } catch (Exception e){
                     System.out.println(e.getMessage());    //沒(méi)有捕獲到異常
                 }
                 try{
                     result  = bar();
                     System.out.println(result);           //輸出100
                 } catch (Exception e){
                     System.out.println(e.getMessage());    //沒(méi)有捕獲到異常
                 }
             }
             //catch中的異常被抑制
             @SuppressWarnings("finally")
             public static int foo() throws Exception
             
          {
                 try {
                     int a = 5/0;
                     return 1;
                 }catch(ArithmeticException amExp) {
                     throw new Exception("我將被忽略,因?yàn)橄旅娴膄inally中使用了return");
                 }finally {
                     return 100;
                 }
             }
             //try中的異常被抑制
             @SuppressWarnings("finally")
             public static int bar() throws Exception
             
          {
                 try {
                     int a = 5/0;
                     return 1;
                 }finally {
                     return 100;
                 }
             }
          }

          finally中的異常會(huì)覆蓋(消滅)前面try或者catch中的異常

          class TestException
          {
             public static void main(String[] args)
             
          {
                 int result;
                 try{
                     result = foo();
                 } catch (Exception e){
                     System.out.println(e.getMessage());    //輸出:我是finaly中的Exception
                 }
                 try{
                     result  = bar();
                 } catch (Exception e){
                     System.out.println(e.getMessage());    //輸出:我是finaly中的Exception
                 }
             }
             //catch中的異常被抑制
             @SuppressWarnings("finally")
             public static int foo() throws Exception
             
          {
                 try {
                     int a = 5/0;
                     return 1;
                 }catch(ArithmeticException amExp) {
                     throw new Exception("我將被忽略,因?yàn)橄旅娴膄inally中拋出了新的異常");
                 }finally {
                     throw new Exception("我是finaly中的Exception");
                 }
             }
             //try中的異常被抑制
             @SuppressWarnings("finally")
             public static int bar() throws Exception
             
          {
                 try {
                     int a = 5/0;
                     return 1;
                 }finally {
                     throw new Exception("我是finaly中的Exception");
                 }
             }
          }

          上面的3個(gè)例子都異于常人的編碼思維,因此我建議:

          • 不要在fianlly中使用return。

          • 不要在finally中拋出異常。

          • 減輕finally的任務(wù),不要在finally中做一些其它的事情,finally塊僅僅用來(lái)釋放資源是最合適的。

          • 將盡量將所有的return寫(xiě)在函數(shù)的最后面,而不是try … catch … finally中。

          如有文章對(duì)你有幫助,

          在看”和轉(zhuǎn)發(fā)是對(duì)我最大的支持!

          剛剛整理好了的第五版《Java大廠面試題》,而且已經(jīng)分類 25 PDF,累計(jì) 2098頁(yè)!

          整理的面試題,內(nèi)容列表


          互聯(lián)網(wǎng)大廠面試題,怎么領(lǐng)???

           注意,不要亂回復(fù) 
          (一定要回復(fù) 面試題 )否則獲取不了

          (加好友,還能邀請(qǐng)進(jìn)Java群 


          覺(jué)得不錯(cuò),請(qǐng)點(diǎn)個(gè)在看

          瀏覽 51
          點(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>
                  在线看片黄色免费Z | 人人爽,人人操 | 先锋影音一区二区三区 | 久久久三级电影片 | 69成人无码|