亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java異常處理機(jī)制深入理解

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

1.初識(shí)異常

我們?cè)趯?xiě)代碼的時(shí)候都或多或少碰到了大大小小的異常,例如:

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

當(dāng)我們數(shù)組越界時(shí),編譯器會(huì)給我們報(bào)數(shù)組越界,并提示哪行出了錯(cuò)。

 再比如:

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

當(dāng)我們嘗試用使用空對(duì)象時(shí),編譯器也會(huì)報(bào)空指針異常:

那么究竟什么是異常?

所謂異常指的就是程序在 運(yùn)行時(shí) 出現(xiàn)錯(cuò)誤時(shí)通知調(diào)用者的一種機(jī)制 .

關(guān)鍵字 "運(yùn)行時(shí)" ,有些錯(cuò)誤是這樣的, 例如將 System.out.println 拼寫(xiě)錯(cuò)了, 寫(xiě)成了

system.out.println. 此時(shí)編譯過(guò)程中就會(huì)出 錯(cuò), 這是 "編譯期" 出錯(cuò).

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

2.異常的基本用法

Java異常處理依賴(lài)于5個(gè)關(guān)鍵字:try、catch、finally、throws、throw。下面來(lái)逐一介紹下。

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

常,系統(tǒng)會(huì)自動(dòng)生成一個(gè)異常對(duì)象,該異常對(duì)象被提交給運(yùn)行環(huán)境,這個(gè)過(guò)程被稱(chēng)為拋出

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

法)。

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

印棧上的錯(cuò)誤信息。但catch語(yǔ)句不能為空,因?yàn)橐坏atch語(yǔ)句寫(xiě)為空,就代表忽略了此

異常。如:

空的catch塊會(huì)使異常達(dá)不到應(yīng)有的目的,即強(qiáng)迫你處理異常的情況。忽略異常就如同忽略

火警信號(hào)一樣——若把火警信號(hào)關(guān)掉了,當(dāng)真正的火災(zāi)發(fā)生時(shí),就沒(méi)有人能看到火警信號(hào)

了?;蛟S你會(huì)僥幸逃過(guò)一劫,或許結(jié)果將是災(zāi)難性的。每當(dāng)見(jiàn)到空的catch塊時(shí),我們都應(yīng)該

警鐘長(zhǎng)鳴。

當(dāng)然也有一種情況可以忽略異常,即關(guān)閉fileinputstream(讀寫(xiě)本地文件)的時(shí)候。因?yàn)槟氵€

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

息,因此不必終止正在進(jìn)行的操作。

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

到try或catch中return或throw之類(lèi)可以終止當(dāng)前方法的代碼時(shí),jvm會(huì)先去執(zhí)行finally中的語(yǔ)

句,當(dāng)finally中的語(yǔ)句執(zhí)行完畢后才會(huì)返回來(lái)執(zhí)行try/catch中的return,throw語(yǔ)句。如果

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

句。finally塊中一般寫(xiě)的是關(guān)閉資源之類(lèi)的代碼。但是我們一般不在finally語(yǔ)句中加入return

語(yǔ)句,因?yàn)樗麜?huì)覆蓋掉try中執(zhí)行的return語(yǔ)句。例如:

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

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

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

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

棧軌跡(異常鏈)。

⑤throw:用于拋出一個(gè)具體的異常對(duì)象。常用于自定義異常類(lèi)中。

ps:

關(guān)于 "調(diào)用棧",方法之間是存在相互調(diào)用關(guān)系的, 這種調(diào)用關(guān)系我們可以用 "調(diào)用棧" 來(lái)描述.

在 JVM 中有一塊內(nèi)存空間稱(chēng)為 "虛擬機(jī)棧" 專(zhuān)門(mén)存儲(chǔ)方法之間的調(diào)用關(guān)系. 當(dāng)代碼中出現(xiàn)異常

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

異常處理流程

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

3.為什么要使用異常?

存在即合理,舉個(gè)例子

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

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

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

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

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

再舉個(gè)例子,當(dāng)玩王者榮耀時(shí),突然斷網(wǎng),他不會(huì)讓你直接程序崩潰吧,而是給你斷線重連的機(jī)會(huì)吧:

我們?cè)儆脗未a演示一把王者榮耀的對(duì)局過(guò)程:

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

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

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

當(dāng)然使用異常的好處還遠(yuǎn)不止于此,我們可以在try、catch語(yǔ)句中加入信息提醒功能,比如你

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

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

務(wù),友友們可以去查查怎么開(kāi)啟呀,我們主旨不是這個(gè)所以不教怎么開(kāi)啟了。演示一下:

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

異常應(yīng)只用于異常的情況

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

這段代碼有什么用?看起來(lái)根本不明顯,這正是它沒(méi)有真正被使用的原因。事實(shí)證明,作為

一個(gè)要對(duì)數(shù)組元素進(jìn)行遍歷的實(shí)現(xiàn)方式,它的構(gòu)想是非常拙劣的。當(dāng)這個(gè)循環(huán)企圖訪問(wèn)數(shù)組

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

忽略(ArrayIndexOutOfBoundsException)的手段來(lái)達(dá)到終止無(wú)限循環(huán)的目的。假定它與數(shù)

組循環(huán)是等價(jià)的,對(duì)于任何一個(gè)Java程序員來(lái)講,下面的標(biāo)準(zhǔn)模式一看就會(huì)明白:

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

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

可能是被誤導(dǎo)了,企圖利用異常機(jī)制提高性能,因?yàn)閖vm每次訪問(wèn)數(shù)組都需要判斷下標(biāo)是否越

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

免。

上面想法有三個(gè)錯(cuò)誤:

1.異常機(jī)制設(shè)計(jì)的初衷是用來(lái)處理不正常的情況,所以JVM很少對(duì)它們進(jìn)行優(yōu)化。

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

3.對(duì)數(shù)組進(jìn)行遍歷的標(biāo)準(zhǔn)模式并不會(huì)導(dǎo)致冗余的檢查。

這個(gè)例子的教訓(xùn)很簡(jiǎn)單:顧名思義,異常應(yīng)只用于異常的情況下,它們永遠(yuǎn)不應(yīng)該用于正常

的控制流。

總結(jié):異常是為了在異常情況下使用而設(shè)計(jì)的,不要用于一般的控制語(yǔ)句。

4. 異常的種類(lèi)

在Java中提供了三種可拋出結(jié)構(gòu):受查異常(checked exception)、運(yùn)行時(shí)異常(run-time exception)和錯(cuò)誤(error)。

(補(bǔ)充)

 4.1 受查異常

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

我們自定義兩個(gè)異常類(lèi)和一個(gè)接口,以及一個(gè)測(cè)試類(lèi)

interface IUser {
    void changePwd() throws SafeException,RejectException;
}
 
class SafeException extends Exception {//因?yàn)槔^承的是execption,所以是受查異常類(lèi)
 
    public SafeException() {
 
    }
 
    public SafeException(String message) {
        super(message);
    }
 
}
 
class RejectException extends Exception {//因?yàn)槔^承的是execption,所以是受查異常類(lèi)
 
    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測(cè)試類(lèi)中user使用方法報(bào)錯(cuò)了,因?yàn)閖ava認(rèn)為checked異常都是可以再編譯階

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

異常,如果程序沒(méi)有處理,則在編譯時(shí)會(huì)發(fā)生錯(cuò)誤,無(wú)法通過(guò)編譯。

解決方案:

①try、catch包裹

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

②拋出異常,將處理動(dòng)作交給上級(jí)調(diào)用者,調(diào)用者在調(diào)用這個(gè)方法時(shí)還是要寫(xiě)一遍try、catch

包裹語(yǔ)句的,所以這個(gè)其實(shí)是相當(dāng)于聲明,讓調(diào)用者知道這個(gè)函數(shù)需要拋出異常

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

4.2非受查異常

派生于error或runtime類(lèi)的所有異常類(lèi)就是非受查異常。

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

不執(zhí)行。

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

來(lái)的,所以也叫作運(yùn)行時(shí)異常。

5.如何使用異常

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

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

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

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

只有在實(shí)現(xiàn)了Cloneable的對(duì)象上才可以被調(diào)用。

 被一個(gè)方法單獨(dú)拋出的受查異常,會(huì)給程序員帶來(lái)非常高的額外負(fù)擔(dān),如果這個(gè)方法還有其

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

catch塊。但當(dāng)只拋出一個(gè)受查異常時(shí),僅僅一個(gè)異常就會(huì)導(dǎo)致該方法不得不處于try塊中,也

就導(dǎo)致了使用這個(gè)方法的類(lèi)都不得不使用try、catch語(yǔ)句,使代碼可讀性也變低了。

受查異常使接口聲明脆弱,比如一開(kāi)始一個(gè)接口只有一個(gè)聲明異常

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

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

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

總結(jié):如果不是非用不可,盡量使用非受查異常,或?qū)⑹懿楫惓^D(zhuǎn)為非受查異常。

6.自定義異常

我們用自定義異常來(lái)實(shí)現(xiàn)一個(gè)登錄報(bào)錯(cuò)的小應(yīng)用

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

test類(lèi)來(lái)測(cè)試運(yùn)行

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("用戶名錯(cuò)誤!");
            }
        }catch (NameException e){
            e.printStackTrace();
        }
        try {
            if(!Test.password.equals(password)){
                throw new PasswordException("密碼錯(cuò)誤");
            }
        }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);
    }
}

關(guān)于異常就到此為止了,怎么感覺(jué)還有點(diǎn)意猶未盡呢?

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

相關(guān)文章

  • Java中的Rocketmq事務(wù)消息詳解

    Java中的Rocketmq事務(wù)消息詳解

    這篇文章主要介紹了Java中的Rocketmq事務(wù)消息詳解,RocketMQ的事務(wù)消息支持在業(yè)務(wù)邏輯與發(fā)送消息之間提供事務(wù)保證,RocketMQ通過(guò)兩階段的方式提供事務(wù)消息的支持,需要的朋友可以參考下
    2023-08-08
  • 基于Java中兩種jersey文件上傳方式

    基于Java中兩種jersey文件上傳方式

    這篇文章主要介紹了基于Java中兩種jersey文件上傳方式的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • javaweb 項(xiàng)目初始配置的方法步驟

    javaweb 項(xiàng)目初始配置的方法步驟

    本文主要介紹了javaweb 項(xiàng)目初始配置的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):稀疏數(shù)組

    java數(shù)據(jù)結(jié)構(gòu)基礎(chǔ):稀疏數(shù)組

    今天帶大家了解一下Java稀疏數(shù)組的相關(guān)知識(shí),文中有非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-08-08
  • java判斷兩個(gè)時(shí)間是不是同一天的方法

    java判斷兩個(gè)時(shí)間是不是同一天的方法

    這篇文章主要介紹了java判斷兩個(gè)時(shí)間是不是同一天的方法,需要的朋友可以參考下
    2014-02-02
  • Spring使用注解實(shí)現(xiàn)Bean的自動(dòng)裝配

    Spring使用注解實(shí)現(xiàn)Bean的自動(dòng)裝配

    大家好,本篇文章主要講的是Spring使用注解實(shí)現(xiàn)Bean的自動(dòng)裝配,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • Java命名規(guī)范

    Java命名規(guī)范

    本文主要介紹了Java命名規(guī)范。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-01-01
  • 使用MDC實(shí)現(xiàn)日志鏈路跟蹤

    使用MDC實(shí)現(xiàn)日志鏈路跟蹤

    這篇文章主要介紹了使用MDC實(shí)現(xiàn)日志鏈路跟蹤,在微服務(wù)環(huán)境中,我們經(jīng)常使用Skywalking、CAT等去實(shí)現(xiàn)整體請(qǐng)求鏈路的追蹤,但是這個(gè)整體運(yùn)維成本高,架構(gòu)復(fù)雜,我們來(lái)使用MDC通過(guò)Log來(lái)實(shí)現(xiàn)一個(gè)輕量級(jí)的會(huì)話事務(wù)跟蹤功能,下面就來(lái)看看具體的過(guò)程吧,需要的朋友可以參考一下
    2022-01-01
  • Java使用RedisTemplate如何根據(jù)前綴獲取key列表

    Java使用RedisTemplate如何根據(jù)前綴獲取key列表

    這篇文章主要介紹了Java使用RedisTemplate如何根據(jù)前綴獲取key列表,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 記一次在idea離線使用maven問(wèn)題(推薦)

    記一次在idea離線使用maven問(wèn)題(推薦)

    這篇文章主要介紹了記一次在idea離線使用maven問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11

最新評(píng)論