电竞比分网-中国电竞赛事及体育赛事平台

分享

Java 異常的捕獲與處理詳解(一)

 oldzhoua 2019-03-14

一、異常的產(chǎn)生

異常是程序之中導(dǎo)致程序中斷的一種指令流,異常一旦出現(xiàn)并且沒(méi)有進(jìn)行合理處理的話,那么程序就將中斷執(zhí)行。
下面,通過(guò)兩個(gè)程序來(lái)進(jìn)行異常產(chǎn)生問(wèn)題的對(duì)比。
(1)不產(chǎn)生異常的程序:

public class Test { public static void main(String args[]) { System.out.println('1、除法計(jì)算開(kāi)始。'); int result = 10 / 2; System.out.println('2、除法計(jì)算結(jié)果:' + result); System.out.println('3、除法計(jì)算結(jié)束。'); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

運(yùn)行結(jié)果:

1、除法計(jì)算開(kāi)始。2、除法計(jì)算結(jié)果:53、除法計(jì)算結(jié)束。
  • 1
  • 2
  • 3

(2)產(chǎn)生異常的程序

public class Test { public static void main(String args[]) { System.out.println('1、除法計(jì)算開(kāi)始。'); int result = 10 / 0; // 會(huì)出現(xiàn)錯(cuò)誤 System.out.println('2、除法計(jì)算結(jié)果:' + result); System.out.println('3、除法計(jì)算結(jié)束。'); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

運(yùn)行結(jié)果:

1、除法計(jì)算開(kāi)始。Exception in thread 'main' java.lang.ArithmeticException: / by zero    at Test.main(Test.java:4)
  • 1
  • 2
  • 3
  • 4

一旦產(chǎn)生異常,我們發(fā)現(xiàn)產(chǎn)生異常的語(yǔ)句以及之后的語(yǔ)句將不再執(zhí)行,默認(rèn)情況下是進(jìn)行異常信息的輸出,而后自動(dòng)結(jié)束程序的執(zhí)行。

現(xiàn)在,我們要做的是:即使程序出現(xiàn)了異常,也要讓程序正確的執(zhí)行完畢。

二、異常的處理

如果希望程序出現(xiàn)異常之后程序依然可以正常的完成的話,那么就可以使用如下的格式進(jìn)行異常的處理:

try { 可能出現(xiàn)異常的語(yǔ)句 ;} [ catch (異常類型 異常對(duì)象) { 處理異常 ;} catch (異常類型 異常對(duì)象) { 處理異常 ;} ... ] [finally { 不管是否出現(xiàn)異常,都執(zhí)行此代碼 ;}]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

現(xiàn)在,使用以上的操作處理異常處理前面除法于是出現(xiàn)的異常:

public class Test {    public static void main(String args[]) {        System.out.println('1、除法計(jì)算開(kāi)始。');        try {            int result = 10 / 0; // 異常            System.out.println('2、除法計(jì)算結(jié)果:' + result); // 之前語(yǔ)句有異常,此語(yǔ)句不再執(zhí)行        } catch (ArithmeticException e) {            System.out.println(e); // 異常處理:輸出錯(cuò)誤信息,java.lang.ArithmeticException:/ by zero        }        System.out.println('3、除法計(jì)算結(jié)束。');    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

運(yùn)行結(jié)果:

1、除法計(jì)算開(kāi)始。java.lang.ArithmeticException: / by zero3、除法計(jì)算結(jié)束。
  • 1
  • 2
  • 3
  • 4

可以發(fā)現(xiàn),加入了異常處理之后,程序中即使有了異常,程序也可以正常的執(zhí)行完畢,但是異常處理時(shí)的錯(cuò)誤輸出信息和之前相比,出錯(cuò)的信息不明確了,那么為了讓錯(cuò)誤的信息更加的完整,一般都會(huì)調(diào)用printStackTrace()方法進(jìn)行異常信息的打印,這個(gè)方法打印的異常信息是最完整的:

public class Test {    public static void main(String args[]) {        System.out.println('1、除法計(jì)算開(kāi)始。');        try {            int result = 10 / 0; // 異常            System.out.println('2、除法計(jì)算結(jié)果:' + result); // 之前語(yǔ)句有異常,此語(yǔ)句不再執(zhí)行        } catch (ArithmeticException e) {            e.printStackTrace(); // 異常處理:輸出錯(cuò)誤信息        }        System.out.println('3、除法計(jì)算結(jié)束。');    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

運(yùn)行結(jié)果:

1、除法計(jì)算開(kāi)始。java.lang.ArithmeticException: / by zero at Test.main(Test.java:5)3、除法計(jì)算結(jié)束。
  • 1
  • 2
  • 3
  • 4

此時(shí)發(fā)現(xiàn),打印的信息是很完整的。

除了try…catch格式處理異常外,還可以使用try…catch..finally:

public class Test {    public static void main(String args[]) {        System.out.println('1、除法計(jì)算開(kāi)始。');        try {            int result = 10 / 1;            System.out.println('2、除法計(jì)算結(jié)果:' + result);        } catch (ArithmeticException e) {            e.printStackTrace();        } finally {            System.out.println('不管是否出現(xiàn)異常都執(zhí)行');        }        System.out.println('3、除法計(jì)算結(jié)束。');    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

運(yùn)行結(jié)果:

1、除法計(jì)算開(kāi)始。2、除法計(jì)算結(jié)果:10不管是否出現(xiàn)異常都執(zhí)行3、除法計(jì)算結(jié)束。
  • 1
  • 2
  • 3
  • 4

但是,對(duì)于之前的程序又有了問(wèn)題:現(xiàn)在執(zhí)行數(shù)學(xué)計(jì)算的兩個(gè)參數(shù),都是由程序默認(rèn)提供,那么如果說(shuō)現(xiàn)在兩個(gè)計(jì)算的參數(shù)通過(guò)初始化參數(shù)傳遞呢?

public class Test {    public static void main(String args[]) {        System.out.println('1、除法計(jì)算開(kāi)始。');        try {            int x = Integer.parseInt(args[0]); // 接收參數(shù)            int y = Integer.parseInt(args[1]); // 接收參數(shù)            int result = x / y;            System.out.println('2、除法計(jì)算結(jié)果:' + result);        } catch (ArithmeticException e) {            e.printStackTrace();        } finally {            System.out.println('不管是否出現(xiàn)異常都執(zhí)行');        }        System.out.println('3、除法計(jì)算結(jié)束。');    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這個(gè)時(shí)候,數(shù)據(jù)由外部傳送,那么就有可能出現(xiàn)以下幾類問(wèn)題:
(1)執(zhí)行時(shí)不輸入?yún)?shù)(java TestDemo),ArrayIndexOutOfBoundsException,未處理;
(2)輸入的參數(shù)不是數(shù)字(java TestDemo a b),NumberFormatException,未處理;
(3)被除數(shù)為0(java TestDemo 10 0),ArithmeticException,已處理。
可以發(fā)現(xiàn),以上的程序?qū)嶋H上是存在三種異常,而程序之中只能夠處理一種,而對(duì)于不能處理的異常,發(fā)現(xiàn)程序依然會(huì)直接中斷執(zhí)行。
加入多個(gè)catch:

public class Test { public static void main(String args[]) { System.out.println('1、除法計(jì)算開(kāi)始。'); try { int x = Integer.parseInt(args[0]); int y = Integer.parseInt(args[1]); int result = x / y; System.out.println('2、除法計(jì)算結(jié)果:' + result); } catch (ArithmeticException e) { e.printStackTrace(); } catch (ArrayIndexOutOfBoundsException e) { e.printStackTrace(); } catch (NumberFormatException e) { e.printStackTrace(); } finally { System.out.println('不管是否出現(xiàn)異常都執(zhí)行'); } System.out.println('3、除法計(jì)算結(jié)束。'); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

現(xiàn)在,程序比之前更健壯了。

三、異常的處理流程

以上已經(jīng)完成了異常的基本處理,但是所有的異常都像之前那樣一條條的判斷似乎是一件不可能完成的任務(wù),因?yàn)槿蘸罂隙〞?huì)接觸到一些不常見(jiàn)的異常信息,那么下面就必須首先研究異常的流程和結(jié)構(gòu)。

先查看兩個(gè)異常類的繼承結(jié)構(gòu):
(1)ArithmeticException:

java.lang.Object    |- java.lang.Throwable         |- java.lang.Exception              |- java.lang.RuntimeException                 |- java.lang.ArithmeticException
  • 1
  • 2
  • 3
  • 4
  • 5

(2)ArrayIndexOutOfBoundsException:

java.lang.Object |- java.lang.Throwable |- java.lang.Exception |- java.lang.RuntimeException |- java.lang.IndexOutOfBoundsException |-java.lang.ArrayIndexOutOfBoundsException
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以發(fā)現(xiàn),所有的異常類型最高的繼承類是Throwable,Throwable下有兩個(gè)子類:
(1)Error:指的是JVM錯(cuò)誤,這個(gè)時(shí)候的程序并沒(méi)有執(zhí)行,無(wú)法處理;
(2)Exception:指的是程序之中出現(xiàn)的錯(cuò)誤信息,可以進(jìn)行異常處理。

通過(guò)繼承關(guān)系可以發(fā)現(xiàn),在進(jìn)行日后異常處理的時(shí)候是以Exception為主,并且可以形成以下的異常處理流程:

11

(1)如果程序中產(chǎn)生了異常,那么JVM根據(jù)異常的類型,實(shí)例化一個(gè)指定異常類的對(duì)象;

(2)如果這時(shí)程序中沒(méi)有任何的異常處理操作,則這個(gè)異常類的實(shí)例化對(duì)象將交給JVM進(jìn)行處理,而JVM的默認(rèn)處理方式就是進(jìn)行異常信息的輸出,而后中斷程序執(zhí)行;

(3)如果程序中存在了異常處理,則會(huì)由try語(yǔ)句捕獲產(chǎn)生的異常類對(duì)象;

(4)與try之后的每一個(gè)catch進(jìn)行匹配,如果匹配成功,則使用指定的catch進(jìn)行處理,如果沒(méi)有匹配成功,則向后面的catch繼續(xù)匹配,如果沒(méi)有任何的catch匹配成功,則這個(gè)時(shí)候?qū)⒔唤oJVM執(zhí)行默認(rèn)處理;

(5)不管是否有異常都會(huì)執(zhí)行finally程序,如果此時(shí)沒(méi)有異常,執(zhí)行完finally,則會(huì)繼續(xù)執(zhí)行程序之中的其他代碼,如果此時(shí)有異常沒(méi)有能夠處理(沒(méi)有一個(gè)catch可以滿足),那么也會(huì)執(zhí)行finally,但是執(zhí)行完finally之后,將默認(rèn)交給JVM進(jìn)行異常的信息輸出,并且程序中斷。

通過(guò)以上的分析可以發(fā)現(xiàn),實(shí)際上catch捕獲異常類型的操作,就和方法接收參數(shù)是一樣的,那么按照之前所學(xué)習(xí)過(guò)的對(duì)象多態(tài)性來(lái)講,所有的異常類都是Exception的子類,那么這個(gè)時(shí)候,實(shí)際上所有的異常都可以使用Exception進(jìn)行接收:

public class Test {    public static void main(String args[]) {        System.out.println('1、除法計(jì)算開(kāi)始。');        try {            int x = Integer.parseInt(args[0]);            int y = Integer.parseInt(args[1]);            int result = x / y;            System.out.println('2、除法計(jì)算結(jié)果:' + result);        } catch (Exception e) {            e.printStackTrace();        } finally {            System.out.println('不管是否出現(xiàn)異常都執(zhí)行');        }        System.out.println('3、除法計(jì)算結(jié)束。');    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

這時(shí)應(yīng)該可以感受到異常處理所帶來(lái)的好處了。但是這種操作也存在一種問(wèn)題:如果在一些異常處理要求嚴(yán)格的項(xiàng)目之中,異常必須分別處理,如果現(xiàn)在異常的處理要求不是很嚴(yán)格,直接編寫(xiě)Exception就足夠了。

未完待續(xù)。。。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多