最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java異常處理機制深入理解

 更新時間:2022年01月18日 17:07:27   作者:海綿寶寶養(yǎng)的的小窩  
如果某個方法不能按照正常的途徑完成任務,就可以通過另一種路徑退出方法。在這種情況下會拋出一個封裝了錯誤信息的對象。此時,這個方法會立刻退出同時不返回任何值。另外,調用這個方法的其他代碼也無法繼續(xù)執(zhí)行,異常處理機制會將代碼執(zhí)行交給異常處理器

1.初識異常

我們在寫代碼的時候都或多或少碰到了大大小小的異常,例如:

public class Test {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        System.out.println(arr[5]);
    }
}

當我們數組越界時,編譯器會給我們報數組越界,并提示哪行出了錯。

 再比如:

class Test{    
    int num = 10;
    public static void main(String[] args) {
        Test test = null;
        System.out.println(test.num);
    }
}

當我們嘗試用使用空對象時,編譯器也會報空指針異常:

那么究竟什么是異常?

所謂異常指的就是程序在 運行時 出現(xiàn)錯誤時通知調用者的一種機制 .

關鍵字 "運行時" ,有些錯誤是這樣的, 例如將 System.out.println 拼寫錯了, 寫成了

system.out.println. 此時編譯過程中就會出 錯, 這是 "編譯期" 出錯.

而運行時指的是程序已經編譯通過得到 class 文件了 , 再由 JVM 執(zhí)行過程中出現(xiàn)的錯誤 .  

2.異常的基本用法

Java異常處理依賴于5個關鍵字:try、catch、finally、throws、throw。下面來逐一介紹下。

①try:try塊中主要放置可能會產生異常的代碼塊。如果執(zhí)行try塊里的業(yè)務邏輯代碼時出現(xiàn)異

常,系統(tǒng)會自動生成一個異常對象,該異常對象被提交給運行環(huán)境,這個過程被稱為拋出

(throw)異常。Java環(huán)境收到異常對象時,會尋找合適的catch塊(在本方法或是調用方

法)。

②catch: catch 代碼塊中放的是出現(xiàn)異常后的處理行為,也可以寫此異常出錯的原因或者打

印棧上的錯誤信息。但catch語句不能為空,因為一旦將catch語句寫為空,就代表忽略了此

異常。如:

空的catch塊會使異常達不到應有的目的,即強迫你處理異常的情況。忽略異常就如同忽略

火警信號一樣——若把火警信號關掉了,當真正的火災發(fā)生時,就沒有人能看到火警信號

了?;蛟S你會僥幸逃過一劫,或許結果將是災難性的。每當見到空的catch塊時,我們都應該

警鐘長鳴。

當然也有一種情況可以忽略異常,即關閉fileinputstream(讀寫本地文件)的時候。因為你還

沒有改變文件的狀態(tài),因此不必執(zhí)行任何恢復動作,并且已經從文件中讀取到所需要的信

息,因此不必終止正在進行的操作。

③finally:finally 代碼塊中的代碼用于處理善后工作, 會在最后執(zhí)行,也一定會被執(zhí)行。當遇

到try或catch中return或throw之類可以終止當前方法的代碼時,jvm會先去執(zhí)行finally中的語

句,當finally中的語句執(zhí)行完畢后才會返回來執(zhí)行try/catch中的return,throw語句。如果

finally中有return或throw,那么將執(zhí)行這些語句,不會在執(zhí)行try/catch中的return或throw語

句。finally塊中一般寫的是關閉資源之類的代碼。但是我們一般不在finally語句中加入return

語句,因為他會覆蓋掉try中執(zhí)行的return語句。例如:

finally將最后try執(zhí)行的return 10覆蓋了,最后結果返回了20.

④throws:在方法的簽名中,用于拋出此方法中的異常給調用者,調用者可以選擇捕獲或者

拋出,如果所有方法(包括main)都選擇拋出(或者沒有合適的處理異常的方式,即異常類

型不匹配)那么最終將會拋給JVM,就會像我們之前沒使用try、catch語句一樣。JVM打印出

棧軌跡(異常鏈)。

⑤throw:用于拋出一個具體的異常對象。常用于自定義異常類中。

ps:

關于 "調用棧",方法之間是存在相互調用關系的, 這種調用關系我們可以用 "調用棧" 來描述.

在 JVM 中有一塊內存空間稱為 "虛擬機棧" 專門存儲方法之間的調用關系. 當代碼中出現(xiàn)異常

的時候, 我們就可以使用 e.printStackTrace() 的方式查看出現(xiàn)異常代碼的調用棧,一般寫在catch語句中。

異常處理流程

  • 程序先執(zhí)行 try 中的代碼
  • 如果 try 中的代碼出現(xiàn)異常, 就會結束 try 中的代碼, 看和 catch 中的異常類型是否匹配.
  • 如果找到匹配的異常類型, 就會執(zhí)行 catch 中的代碼
  • 如果沒有找到匹配的異常類型, 就會將異常向上傳遞到上層調用者.
  • 無論是否找到匹配的異常類型, finally 中的代碼都會被執(zhí)行到(在該方法結束之前執(zhí)行).
  • 如果上層調用者也沒有處理的了異常, 就繼續(xù)向上傳遞.
  • 一直到 main 方法也沒有合適的代碼處理異常, 就會交給 JVM 來進行處理, 此時程序就會異常終止.

3.為什么要使用異常?

存在即合理,舉個例子

             //不使用異常
        int[] arr = {1, 2, 3};
 
        System.out.println("before");
 
        System.out.println(arr[100]);
 
        System.out.println("after");

當我們不使用異常時,發(fā)現(xiàn)出現(xiàn)異常程序直接崩潰,后面的after也沒有打印。

               //使用異常
        int[] arr = {1, 2, 3};
 
        try {
 
            System.out.println("before");
 
            System.out.println(arr[100]);
 
            System.out.println("after");
 
        } catch (ArrayIndexOutOfBoundsException e) {
            //	打印出現(xiàn)異常的調用棧
 
            e.printStackTrace();
 
        }
 
        System.out.println("after try catch");

當我們使用了異常,雖然after也沒有執(zhí)行,但程序并沒有直接崩潰,后面的sout語句還是執(zhí)行了

這不就是異常的作用所在嗎?

再舉個例子,當玩王者榮耀時,突然斷網,他不會讓你直接程序崩潰吧,而是給你斷線重連的機會吧:

我們再用偽代碼演示一把王者榮耀的對局過程:

不使用異常處理
boolean ret = false;
 
ret = 登陸游戲();
 
if (!ret) {
 
處理登陸游戲錯誤;
 
return;
 
}
 
ret = 開始匹配();
 
if (!ret) {
 
處理匹配錯誤;
 
return;
 
}
ret = 游戲確認();
 
if (!ret) {
 
處理游戲確認錯誤;
 
return;
 
}
ret = 選擇英雄();
 
if (!ret) {
 
處理選擇英雄錯誤;
 
return;
 
}
 
ret = 載入游戲畫面();
 
if (!ret) {
 
處理載入游戲錯誤;
 
return;
 
}
 
......
使用異常處理
try {
 
登陸游戲();
 
開始匹配();
 
游戲確認();
 
選擇英雄();
 
載入游戲畫面();
 
...
 
} catch (登陸游戲異常) {
 
處理登陸游戲異常;
 
} catch (開始匹配異常) {
 
處理開始匹配異常;
 
} catch (游戲確認異常) {
 
處理游戲確認異常;
 
} catch (選擇英雄異常) {
 
處理選擇英雄異常;
 
} catch (載入游戲畫面異常) {
 
處理載入游戲畫面異常;
 
}
......

我們能明顯的看到不使用異常時,正確流程和錯誤處理代碼混在一起,不易于分辨,而用了

異常后,能更易于理解代碼。

當然使用異常的好處還遠不止于此,我們可以在try、catch語句中加入信息提醒功能,比如你

開發(fā)了一個軟件,當那個軟件出現(xiàn)異常時,發(fā)個信息提醒你及時去修復。博主就做了一個小

小的qq郵箱信息提醒功能,源碼在碼云,有興趣的可以去看看呀!需要配置qq郵箱pop3服

務,友友們可以去查查怎么開啟呀,我們主旨不是這個所以不教怎么開啟了。演示一下:

別群發(fā)消息哦,不然可能會被封號???

異常應只用于異常的情況

try{
   int i = 0;
   while(true)
       System.out.println(a[i++]);
}catch(ArrayIndexOutOfBoundsException e){
 }

這段代碼有什么用?看起來根本不明顯,這正是它沒有真正被使用的原因。事實證明,作為

一個要對數組元素進行遍歷的實現(xiàn)方式,它的構想是非常拙劣的。當這個循環(huán)企圖訪問數組

邊界之外的第一個數組元素時,用拋出(throw)、捕獲(catch)、

忽略(ArrayIndexOutOfBoundsException)的手段來達到終止無限循環(huán)的目的。假定它與數

組循環(huán)是等價的,對于任何一個Java程序員來講,下面的標準模式一看就會明白:

for(int m : a)
   System.out.println(m);

為什么優(yōu)先異常的模式,而不是用行之有效標準模式呢?

可能是被誤導了,企圖利用異常機制提高性能,因為jvm每次訪問數組都需要判斷下標是否越

界,他們認為循環(huán)終止被隱藏了,但是在foreach循環(huán)中仍然可見,這無疑是多余的,應該避

免。

上面想法有三個錯誤:

1.異常機制設計的初衷是用來處理不正常的情況,所以JVM很少對它們進行優(yōu)化。

2.代碼放在try…catch中反而阻止jvm本身要執(zhí)行的某些特定優(yōu)化。

3.對數組進行遍歷的標準模式并不會導致冗余的檢查。

這個例子的教訓很簡單:顧名思義,異常應只用于異常的情況下,它們永遠不應該用于正常

的控制流。

總結:異常是為了在異常情況下使用而設計的,不要用于一般的控制語句。

4. 異常的種類

在Java中提供了三種可拋出結構:受查異常(checked exception)、運行時異常(run-time exception)和錯誤(error)。

(補充)

 4.1 受查異常

什么是受查異常?只要不是派生于error或runtime的異常類都是受查異常。舉個例子:

我們自定義兩個異常類和一個接口,以及一個測試類

interface IUser {
    void changePwd() throws SafeException,RejectException;
}
 
class SafeException extends Exception {//因為繼承的是execption,所以是受查異常類
 
    public SafeException() {
 
    }
 
    public SafeException(String message) {
        super(message);
    }
 
}
 
class RejectException extends Exception {//因為繼承的是execption,所以是受查異常類
 
    public RejectException() {
 
    }
    public RejectException(String message) {
        super(message);
    }
}
 
public class Test {
    public static void main(String[] args) {
        IUser user = null;
        user.changePwd();
    }
}

我們發(fā)現(xiàn)test測試類中user使用方法報錯了,因為java認為checked異常都是可以再編譯階

段被處理的異常,所以它強制程序處理所有的checked異常,java程序必須顯式處checked

異常,如果程序沒有處理,則在編譯時會發(fā)生錯誤,無法通過編譯。

解決方案:

①try、catch包裹

 IUser user = null;
        try {
            user.changePwd();
        }catch (SafeException e){
            e.printStackTrace();
        }
        catch (RejectException e){
            e.printStackTrace();
        }

②拋出異常,將處理動作交給上級調用者,調用者在調用這個方法時還是要寫一遍try、catch

包裹語句的,所以這個其實是相當于聲明,讓調用者知道這個函數需要拋出異常

public static void main(String[] args) throws SafeException, RejectException {
        IUser user = null;
        user.changePwd();
    }

4.2非受查異常

派生于error或runtime類的所有異常類就是非受查異常。

可以這么說,我們現(xiàn)在寫程序遇到的異常大部分都是非受查異常,程序直接崩潰,后面的也

不執(zhí)行。

像空指針異常、數組越界異常、算術異常等,都是非受查異常。由編譯器運行時給你檢查出

來的,所以也叫作運行時異常。

5.如何使用異常

避免不必要的使用受查異常

如果不能阻止異常條件的產生,并且一旦產生異常,程序員可以立即采取有用的動作,這種

受查異常才是可取的。否則,更適合用非受查異常。這種例子就是

CloneNotSuppportedException(受查異常)。它是被Object.clone拋出來的,Object.clone

只有在實現(xiàn)了Cloneable的對象上才可以被調用。

 被一個方法單獨拋出的受查異常,會給程序員帶來非常高的額外負擔,如果這個方法還有其

他的受查異常,那么它被調用是一定已經出現(xiàn)在一個try塊中,所以這個異常只需要另外一個

catch塊。但當只拋出一個受查異常時,僅僅一個異常就會導致該方法不得不處于try塊中,也

就導致了使用這個方法的類都不得不使用try、catch語句,使代碼可讀性也變低了。

受查異常使接口聲明脆弱,比如一開始一個接口只有一個聲明異常

interfaceUser{  
    //修改用戶名,拋出安全異常  
    publicvoid changePassword() throws MySecurityExcepiton; 
} 

但隨著系統(tǒng)開發(fā),實現(xiàn)接口的類越來越多,突然發(fā)現(xiàn)changePassword還需要拋出另一個異

常,那么實現(xiàn)這個接口的所有類也都要追加對這個新異常的處理,這個工程量就很大了。

總結:如果不是非用不可,盡量使用非受查異常,或將受查異常轉為非受查異常。

6.自定義異常

我們用自定義異常來實現(xiàn)一個登錄報錯的小應用

class NameException extends RuntimeException{//用戶名錯誤異常
    public NameException(String message){
        super(message);
    }
}
class PasswordException extends RuntimeException{//密碼錯誤異常
    public PasswordException(String message){
        super(message);
    }
}

test類來測試運行

public class Test {
    private static final String name = "bit";
    private static final String password ="123";
 
    public static void Login(String name,String password) throws NameException,PasswordException{
        try{
            if(!Test.name.equals(name)){
                throw new NameException("用戶名錯誤!");
            }
        }catch (NameException e){
            e.printStackTrace();
        }
        try {
            if(!Test.password.equals(password)){
                throw new PasswordException("密碼錯誤");
            }
        }catch (PasswordException e){
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        String password = scanner.nextLine();
        Login(name,password);
    }
}

關于異常就到此為止了,怎么感覺還有點意猶未盡呢?

到此這篇關于Java異常處理機制深入理解的文章就介紹到這了,更多相關Java 異常處理機制內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MybatisPlus中saveBatch方法的使用

    MybatisPlus中saveBatch方法的使用

    本文介紹了MyBatisPlus中的saveBatch方法的使用及其實現(xiàn)原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-11-11
  • Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新

    Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新

    這篇文章主要介紹了Springboot使用thymeleaf動態(tài)模板實現(xiàn)刷新,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • java身份證合法性校驗工具類實例代碼

    java身份證合法性校驗工具類實例代碼

    這篇文章主要給大家介紹了關于java身份證合法性校驗工具類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-09-09
  • java Socket無法完全接收返回內容的解決方案

    java Socket無法完全接收返回內容的解決方案

    這篇文章主要介紹了java Socket無法完全接收返回內容的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java 加密解密基礎分類及模式歸納整理

    Java 加密解密基礎分類及模式歸納整理

    這篇文章主要介紹了Java加密解密基礎分類方法匯總的相關資料,需要的朋友可以參考下
    2017-04-04
  • fastjson 使用方法詳細介紹

    fastjson 使用方法詳細介紹

    Fastjson是一個Java語言編寫的JSON處理器,由阿里巴巴公司開發(fā)。接下來通過本文給大家分享fastjson 使用方法詳細介紹,感興趣的朋友一起看看吧
    2017-11-11
  • java反射常用方法案例詳解

    java反射常用方法案例詳解

    Java反射指的是一個機制,這種機制可以在Java程序運行時(動態(tài))實例化對象、讀寫屬性、調用方法,這篇文章主要介紹了java反射常用方法,需要的朋友可以參考下
    2023-06-06
  • Spring使用AOP完成統(tǒng)一結果封裝實例demo

    Spring使用AOP完成統(tǒng)一結果封裝實例demo

    這篇文章主要介紹了Spring使用AOP完成統(tǒng)一結果封裝,本文通過實現(xiàn)demo給大家詳細講解,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • Springboot Websocket Stomp 消息訂閱推送

    Springboot Websocket Stomp 消息訂閱推送

    本文主要介紹了Springboot Websocket Stomp 消息訂閱推送,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-07-07
  • java簡單選擇排序實例

    java簡單選擇排序實例

    這篇文章主要為大家詳細介紹了java簡單選擇排序實例,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評論

库伦旗| 连山| 葫芦岛市| 长治市| 万宁市| 团风县| 宁远县| 阿坝县| 塔城市| 观塘区| 印江| 永平县| 清水县| 日土县| 普兰县| 绥宁县| 宝应县| 正宁县| 吴川市| 黎城县| 昭平县| 莲花县| 陇西县| 光山县| 鄯善县| 岳阳县| 和林格尔县| 万州区| 周宁县| 青海省| 东台市| 南丹县| 集安市| 新野县| 德昌县| 玉屏| 枞阳县| 武鸣县| 阿图什市| 安图县| 鄄城县|