異常的捕獲及處理

1. 異常的產(chǎn)生

異常是導(dǎo)致程序中斷執(zhí)行的一種指令流笙隙,異常一旦出現(xiàn)且沒有對其進(jìn)行合理的處理,程序就中斷執(zhí)行坎缭。
范例:不產(chǎn)生異常的代碼

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.開始除法計(jì)算");
        System.out.println("2.計(jì)算 " + (10/2));
        System.out.println("3.結(jié)束除法計(jì)算");
    }
}

輸出顯示:

1.開始除法計(jì)算
2.計(jì)算 5
3.結(jié)束除法計(jì)算

范例:產(chǎn)生異常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.開始除法計(jì)算");
        //此行代碼產(chǎn)生異常
        System.out.println("2.計(jì)算 " + (10 / 0));     
        System.out.println("3.結(jié)束除法計(jì)算");
    }
}

輸出顯示:

1.開始除法計(jì)算
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)

異常一旦發(fā)生竟痰,產(chǎn)生異常的語句及之后的語句都不再執(zhí)行,默認(rèn)輸出異常信息后掏呼,程序自動(dòng)結(jié)束執(zhí)行凯亮。
我們要做的就是:即使出現(xiàn)了異常,也應(yīng)該讓程序正確的執(zhí)行完畢哄尔。

2. 處理異常

如果想要進(jìn)行異常的處理,在Java之中提供了三個(gè)關(guān)鍵字:try柠并、catch岭接、finally,而這三個(gè)關(guān)鍵字的使用語法如下:

//“[]” 表示有可能使用到
try {
    //有可能出現(xiàn)異常的語句
} [ catch(異常類型 對象){
    //異常處理
}catch(異常類型 對象){
    //異常處理
}...] [finally {
    //不管是否出現(xiàn)異常臼予,都執(zhí)行的代碼
}]

范例:應(yīng)用異常處理try...catch

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.開始除法計(jì)算");
        try {
            System.out.println("2.計(jì)算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        }
        System.out.println("3.結(jié)束除法計(jì)算");
    }
}

輸出顯示:

1.開始除法計(jì)算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:6)
3.結(jié)束除法計(jì)算

由于使用了異常處理鸣戴,即使程序出現(xiàn)了異常,也可以正常的執(zhí)行完畢粘拾。而且使用異常類中提供的printStackTrace()方法窄锅,可以完整的輸出異常信息。
范例:使用try...catch...finally

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.開始除法計(jì)算");
        try {
            System.out.println("2.計(jì)算 " + (10 / 0));     
        } catch (ArithmeticException e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有異常缰雇,都執(zhí)行此語句入偷!");
        }
        System.out.println("3.結(jié)束除法計(jì)算");
    }
}

輸出顯示:

1.開始除法計(jì)算
java.lang.ArithmeticException: / by zero
    at ExceptionDemo.main(ExceptionDemo.java:5)
不管是否有異常,都執(zhí)行此語句械哟!
3.結(jié)束除法計(jì)算

3. 異常的處理流程(核心)

首先觀察兩個(gè)異常類的繼承結(jié)構(gòu):


觀察兩個(gè)異常類

觀察可以發(fā)現(xiàn)所有的異常類都是Throwable的子類疏之,而在Throwable下有兩個(gè)子類:
Error 和 Exception

  • Error :指的是JVM錯(cuò)誤,即:此時(shí)的程序還沒有執(zhí)行暇咆,用戶還無法處理锋爪;
  • Exception :指的是程序運(yùn)行中產(chǎn)生的異常丙曙,用戶可以處理。

也就是所謂的異常處理指的就是所有的Exception以及它的子類異常其骄。

面試題:Java中的異常處理流程

異常處理流程

范例:使用Exception處理異常

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println("1.開始除法計(jì)算");
        try {
            int x = Integer.parseInt(args[0]);
            int y = Integer.parseInt(args[1]);
            System.out.println("2.計(jì)算 " + (x / y));
            System.out.println("**************");
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            System.out.println("不管是否有異常亏镰,都執(zhí)行此語句!");
        }
        System.out.println("3.結(jié)束除法計(jì)算");
    }
}

所有的異常都使用了Exception進(jìn)行處理拯爽,所以在程序之中不用再去關(guān)心到底使用哪一個(gè)異常索抓。
注意:

  • 在編寫多個(gè)catch捕獲異常的時(shí)候,捕獲范圍大的異常一定要放在捕獲異常范圍小的異常之后某抓,否則編譯錯(cuò)誤纸兔。
  • 雖然直接捕獲Exception比較方便,但是這樣也不好否副,因?yàn)檫@樣所有的異常都會(huì)安裝同一方式處理汉矿。

4. throws關(guān)鍵字

throws關(guān)鍵字主要用于方法聲明上,指的是當(dāng)方法之中出現(xiàn)異常后交由被調(diào)用處來進(jìn)行處理备禀。
范例:使用throws

class MyMath {
    //存在throws關(guān)鍵字洲拇,表示此方法里面產(chǎn)生的異常交給調(diào)用處處理
    public static int div(int x , int y) throws Exception {
        return x / y ;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

調(diào)用了具有throws聲明的方法之后,不管操作是否出現(xiàn)異常曲尸,都必須使用try...catch來進(jìn)行異常的處理赋续。

5. throw關(guān)鍵字

在程序之中直接使用throw手工拋出一個(gè)異常類的實(shí)例化對象。
范例:手工拋出異常

public class ThrowDemo {
    public static void main(String[] args) {
        try {
            throw new Exception("自己定義的異常");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

輸出顯示:

java.lang.Exception: 自己定義的異常
    at ThrowDemo.main(ThrowDemo.java:4)

面試題:throws 和 throw的區(qū)別

  • throws:在方法的聲明上使用另患,表示此方法在調(diào)用時(shí)必須處理異常纽乱;
  • throw:指的是在方法中人為拋出一個(gè)異常類對象(這個(gè)異常類對象可能是自己實(shí)例化或是拋出已知存在)。

6. 重要的代碼模型:異常的使用格式

需求:要求定義一個(gè)div()方法昆箕,在進(jìn)行計(jì)算之前打印提示信息鸦列,計(jì)算結(jié)束也打印提示信息,如果在計(jì)算之中產(chǎn)生了異常鹏倘,則交給被調(diào)用處進(jìn)行處理薯嗤。
范例:不出錯(cuò)的代碼

class MyMath {
    public static int div(int x , int y) {
        int result = 0;
        System.out.println("*** 1. 計(jì)算開始 ***");
        result = x / y;
        System.out.println("*** 1. 計(jì)算結(jié)束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
            System.out.println(MyMath.div(10 , 2));
    }
}

但是以上代碼中的除法操作不一定永遠(yuǎn)都正常完成,所以應(yīng)該進(jìn)行合理的處理纤泵。首先骆姐,如果方法出現(xiàn)異常,必須交由調(diào)用處處理捏题,所以應(yīng)該在方法上使用throws拋出

class MyMath {
    //存在throws關(guān)鍵字玻褪,表示此方法里面產(chǎn)生的異常交給調(diào)用處處理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 計(jì)算開始 ***");
        result = x / y;
        System.out.println("*** 1. 計(jì)算結(jié)束 ***");
        return result;
        
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 2));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果以上代碼真的出錯(cuò),程序的有些內(nèi)容就不執(zhí)行了涉馅,所以修改如下:

class MyMath {
    //存在throws關(guān)鍵字敞斋,表示此方法里面產(chǎn)生的異常交給調(diào)用處處理
    public static int div(int x , int y) throws Exception {
        int result = 0;
        System.out.println("*** 1. 計(jì)算開始 ***");
        try {
            result = x / y;
        } catch (Exception e) {
            throw e;    //繼續(xù)拋異常
        } finally {
            System.out.println("*** 1. 計(jì)算結(jié)束 ***");
        }
        return result;
    }
}
public class ThrowsDemo {
    public static void main(String[] args) {
        try {
            System.out.println(MyMath.div(10 , 0));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

輸出顯示:

*** 1. 計(jì)算開始 ***
*** 1. 計(jì)算結(jié)束 ***
java.lang.ArithmeticException: / by zero
    at MyMath.div(ThrowsDemo.java:7)
    at ThrowsDemo.main(ThrowsDemo.java:19)

7. RuntimeException 類

先觀察一段代碼:

public class RuntimeExceptionDemo {
    public static void main(String[] args) {
        int temp = Integer.parseInt("100");
        System.out.println(temp);   //輸出100
    }
}

在看一下parseInt()方法的定義:
public static int parseInt(String s) throws NumberFormatException
此時(shí)parseInt()方法上拋出了NumberFormatException肄方,按理說袭艺,應(yīng)該進(jìn)行強(qiáng)制性的異常捕獲,但是現(xiàn)在并沒有強(qiáng)制性操作捻浦,所以來看下NumberFormatException的繼承結(jié)構(gòu):

java.lang.Object 
    java.lang.Throwable 
        java.lang.Exception 
            java.lang.RuntimeException → 運(yùn)行時(shí)異常
                java.lang.IllegalArgumentException 
                    java.lang.NumberFormatException

在Java里面為了方便用戶代碼的編寫,專門提供了RuntimeException類桥爽,其特征為:程序在編譯的時(shí)候不會(huì)強(qiáng)制性要求用戶處理異常朱灿,用戶可以根據(jù)需求選擇性的進(jìn)行處理,如果沒有處理又發(fā)生了異常钠四,則交給JVM默認(rèn)處理盗扒。

面試題:Exception 和 RuntimeException的區(qū)別?列舉幾個(gè)常見的RuntimeException子類:

  • Exception是RuntimeException的父類缀去;
  • 使用Exception定義的異常必須要被處理侣灶,而RuntimeException的異常可以選擇性處理:
  • 常見的RuntimeException:ArithmeticException缕碎、NullPointerException褥影、ClassCastException。

8. assert關(guān)鍵字—斷言(了解)

assert關(guān)鍵字是在JDK1.4的時(shí)候引入的咏雌,其主要的功能就是進(jìn)行斷言凡怎。斷言:指的是程序執(zhí)行到某行代碼處判斷是否是預(yù)期的結(jié)果。
范例:觀察斷言

public class AssertDemo {
    public static void main(String[] args) {
        int num = 10;
        //中間可能經(jīng)過了多行代碼操作num的內(nèi)容
        //期望中的內(nèi)容是20
        assert num == 20 : "num的內(nèi)容不是20";
        System.out.println("num = " + num);
    }
}

正常執(zhí)行輸出顯示:
num = 10
啟用斷言執(zhí)行:java -ea AssertDemo

Exception in thread "main" java.lang.AssertionError: num的內(nèi)容不是20
        at AssertDemo.main(AssertDemo.java:6)

9. 自定義異常

Java本身提供了大量的異常赊抖,但是這些異常實(shí)際工作中并不夠去使用统倒,所以就需要用戶自定義異常類。如果開發(fā)自定義的異常類可以選擇繼承Exception或者RuntimeException類氛雪。
范例:定義AddException

class AddException extends Exception{
    public AddException(String msg) {
        super(msg);
    }
}

public class AddExceptionDemo{
    public static void main(String[] args) {
        int num = 20;
        try {
            if (num > 0) {  //出現(xiàn)錯(cuò)誤房匆,應(yīng)該產(chǎn)生異常
                throw new AddException("數(shù)值傳遞過大");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上代碼知識(shí)介紹自定義異常的形式,但是并不能說明自定義異常的實(shí)際使用报亩。

總結(jié)

  1. Exception的父類是Throwable坛缕,但是在編寫代碼的時(shí)候盡量不要使用Throwable,因?yàn)門hrowable類有子類Error捆昏,用戶能處理的只有Exception類
  2. 異常處理的標(biāo)準(zhǔn)格式:try、catch毙沾、finally骗卜、throw、throws左胞;
  3. RuntimeException與Exception的區(qū)別寇仓。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市烤宙,隨后出現(xiàn)的幾起案子遍烦,更是在濱河造成了極大的恐慌,老刑警劉巖躺枕,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件服猪,死亡現(xiàn)場離奇詭異供填,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)罢猪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進(jìn)店門近她,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膳帕,你說我怎么就攤上這事粘捎。” “怎么了危彩?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵攒磨,是天一觀的道長。 經(jīng)常有香客問我汤徽,道長娩缰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任泻骤,我火速辦了婚禮漆羔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狱掂。我一直安慰自己演痒,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布趋惨。 她就那樣靜靜地躺著鸟顺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪器虾。 梳的紋絲不亂的頭發(fā)上讯嫂,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機(jī)與錄音兆沙,去河邊找鬼欧芽。 笑死,一個(gè)胖子當(dāng)著我的面吹牛葛圃,可吹牛的內(nèi)容都是我干的千扔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼库正,長吁一口氣:“原來是場噩夢啊……” “哼曲楚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起褥符,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤龙誊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后喷楣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趟大,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹤树,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了护昧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魂迄。...
    茶點(diǎn)故事閱讀 39,754評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖惋耙,靈堂內(nèi)的尸體忽然破棺而出捣炬,到底是詐尸還是另有隱情,我是刑警寧澤绽榛,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布湿酸,位于F島的核電站,受9級特大地震影響灭美,放射性物質(zhì)發(fā)生泄漏推溃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一届腐、第九天 我趴在偏房一處隱蔽的房頂上張望铁坎。 院中可真熱鬧,春花似錦犁苏、人聲如沸硬萍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朴乖。三九已至,卻和暖如春助赞,著一層夾襖步出監(jiān)牢的瞬間买羞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工雹食, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留畜普,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓群叶,卻偏偏與公主長得像漠嵌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子盖呼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評論 2 354

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