7.異常處理

2022-12-26 10:18:27 來源:51CTO博客

一、異常概述與異常體系結(jié)構

在使用計算機語言進行項目開發(fā)的過程中,即使程序員把代碼寫得盡善盡美, 在系統(tǒng)的運行過程中仍然會遇到一些問題,因為很多問題不是靠代碼能夠避 免的,比如:客戶輸入數(shù)據(jù)的格式,讀取文件是否存在,網(wǎng)絡是否始終保持通暢等等。


【資料圖】

異常:在Java語言中,將程序執(zhí)行中發(fā)生的不正常情況稱為“異常” 。 (開發(fā)過程中的語法錯誤和邏輯錯誤不是異常)Java程序在執(zhí)行過程中所發(fā)生的異常事件可分為兩類:Error:Java虛擬機無法解決的嚴重問題。如:JVM系統(tǒng)內(nèi)部錯誤、資源 耗盡等嚴重情況。比如:StackOverflowError和==??OOM??==。一般不編寫針對性 的代碼進行處理。Exception:其他因編程錯誤或偶然的外在因素導致的一般性問題,可以使用針對想的代碼進行處理。例如:空指針訪問試圖讀取不存在的文件網(wǎng)絡連接中斷數(shù)組角標越界一般有兩種解決方法:一是遇到錯誤就終止程序 的運行。另一種方法是由程序員在編寫程序時,就考慮到錯誤的 檢測、錯誤消息的提示,以及錯誤的處理。捕獲錯誤最理想的是在編譯期間,但有的錯誤只有在運行時才會發(fā)生。 比如:除數(shù)為0,數(shù)組下標越界等分類:編譯時異常運行時異常
1.運行時異常
是指編譯器不要求強制處置的異常。一般是指編程時的邏輯錯誤,是程序員應該積極避免其出現(xiàn)的異常。java.lang.RuntimeException類及他的子類都是運行時異常。對于這類一場,可以不做處理,因為這類異常很普遍,若全處理可能會對程序的可讀性和運行效率產(chǎn)生影響。
2.編譯時異常
是指編譯器必須要求處置的異常。即程序在運行時由于外界因素造成的一般性異常。==編譯器要求HJava程序必須捕獲或聲明所有編譯時的異常。對于這類異常,如果程序不處理,可能會帶來意想不到的結(jié)果。

二、常見異常

java.lang.RuntimeExceptionClasscastExceptionArrayIndexOutOfBoundsExceptionNullPointerExceptionArithmeticException 算術運算異常 整數(shù)0做了分母NumberFormatException 數(shù)字格式化異常InputMismatchException 輸入不匹配異常,即輸入的值數(shù)據(jù)類型與設置的不匹配java.io.IOExeptionFileNotFoundExceptionEOFExceptionjava.lang.ClassNotFoundExceptionjava.lang.InterruptedException 一個線程處于等待,睡眠,或者占用,也就是說阻塞狀態(tài),而這時線程被中斷就會拋出這類錯誤java.io.FileNotFoundExceptionjava.sql.SQLException

三、異常處理機制一: try-catch-finally

在編寫程序時,經(jīng)常要在可能出現(xiàn)錯誤的地方加上檢測的代碼, 如進行x/y運算時,要檢測分母為0,數(shù)據(jù)為空,輸入的不是數(shù)據(jù) 而是字符等。過多的if-else分支會導致程序的代碼加長、臃腫, 可讀性差。因此采用異常處理機制。

Java異常處理

Java采用的異常處理機制,是將異常處理的程序代碼集中在一起, 與正常的程序代碼分開,使得程序簡潔、優(yōu)雅,并易于維護。

Java異常處理的方式:

方式一:try-catch-finally

方式二:throws + 異常類型

Java提供的是異常處理的抓拋模型。Java程序的執(zhí)行過程中如出現(xiàn)異常,會生成一個異常類對象, 該異常對象將被提交給Java運行時系統(tǒng),這個過程稱為拋出 (throw)異常。異常對象的生成由虛擬機自動生成:程序運行過程中,虛擬機檢測到程序發(fā)生了問題,如果在當 前代碼中沒有找到相應的處理程序,就會在后臺自動創(chuàng)建一個對應異常類的實例 對象并拋出——自動拋出由開發(fā)人員手動創(chuàng)建:Exception exception = new ClassCastException();——創(chuàng) 建好的異常對象不拋出對程序沒有任何影響,和創(chuàng)建一個普通對象一樣

為保證程序正常執(zhí)行,代碼必須對可能出現(xiàn)的異常進行處理。

如果一個方法內(nèi)拋出異常,該異常對象會被拋給調(diào)用者方法中處 理。如果異常沒有在調(diào)用者方法中處理,它繼續(xù)被拋給這個調(diào)用 方法的上層方法。這個過程將一直繼續(xù)下去,直到異常被處理。 這一過程稱為捕獲(catch)異常。如果一個異常回到main()方法,并且main()也不處理,則程序運行終止。程序員通常只能處理Exception,而對Error無能為力。

異常處理是通過try-catch-finally語句實現(xiàn)的。

try{...... //可能產(chǎn)生異常的代碼}catch( ExceptionName1 e ){...... //當產(chǎn)生ExceptionName1型異常時的處置措施}catch( ExceptionName2 e ){...... //當產(chǎn)生ExceptionName2型異常時的處置措施}[ finally{...... //無論是否發(fā)生異常,都無條件執(zhí)行的語句} ]
try捕獲異常的第一步是用try{…}語句塊選定捕獲異常的范圍,將可能出現(xiàn) 異常的代碼放在try語句塊中。catch (Exceptiontype e)在catch語句塊中是對異常對象進行處理的代碼。每個try語句塊可以伴隨 一個或多個catch語句,用于處理可能產(chǎn)生的不同類型的異常對象。

如果明確知道產(chǎn)生的是何種異常,可以用該異常類作為catch的參數(shù);也可以用其父類作為catch的參數(shù)。

比 如 : 可 以 用 ArithmeticException 類 作 為 參 數(shù) 的 地 方 , 就 可 以 用 RuntimeException類作為參數(shù),或者用所有異常的父類Exception類作為參數(shù)。 但不能是與ArithmeticException類無關的異常,如NullPointerException(catch 中的語句將不會執(zhí)行)。

捕獲異常的有關信息:與其它對象一樣,可以訪問一個異常對象的成員變量或調(diào)用它的方法。getMessage() 獲取異常信息,返回字符串printStackTrace() 獲取異常類名和異常信息,以及異常出 現(xiàn)在程序中的位置。返回值void。finally捕獲異常的最后一步是通過finally語句為異常處理提供一個 統(tǒng)一的出口,使得在控制流轉(zhuǎn)到程序的其它部分以前,能夠 對程序的狀態(tài)作統(tǒng)一的管理。不論在try代碼塊中是否發(fā)生了異常事件,catch語句是否執(zhí) 行,catch語句是否有異常,catch語句中是否有return, finally塊中的語句都會被執(zhí)行。finally語句和catch語句是任選的
不捕獲異常時的情況
前面使用的異常都是RuntimeException類或是它的子類,這些類的異常的特點是:即使沒有使用try和catch捕獲,Java自己也能捕獲,并且編譯通過 ( 但運行時會發(fā)生異常使得程序運行終止 )。如果拋出的異常是IOException等類型的非運行時異常,則必須捕獲,否則 編譯錯誤。也就是說,我們必須處理編譯時異常,將異常進行捕捉,轉(zhuǎn)化為運行時異常

四、異常處理機制二: throws

1.聲明拋出異常
聲明拋出異常是Java中處理異常的第二種方式如果一個方法(中的語句執(zhí)行時)可能生成某種異常,但是并不能確定如何處理這 種異常,則此方法應顯示地聲明拋出異常,表明該方法將不對這些異常進行處理, 而由該方法的調(diào)用者負責處理。在方法聲明中用throws語句可以聲明拋出異常的列表,throws后面的異常類型可 以是方法中產(chǎn)生的異常類型,也可以是它的父類。聲明拋出異常舉例:
public void readFile(String file) throws FileNotFoundException {……// 讀文件的操作可能產(chǎn)生FileNotFoundException類型的異常FileInputStream fis = new FileInputStream(file);..……}
2.重寫方法聲明拋出異常的原則
重寫方法不能拋出比被重寫方法范圍更大的異常類型。在多態(tài)的情況下, 對methodA()方法的調(diào)用-異常的捕獲按父類聲明的異常處理。
public class A {public void methodA() throws IOException {……} }public class B1 extends A {public void methodA() throws FileNotFoundException {……} }public class B2 extends A {public void methodA() throws Exception { //報錯……} }

五、手動拋出異常

Java異常類對象除在程序執(zhí)行過程中出現(xiàn)異常時由系統(tǒng)自動生成并 拋出,也可根據(jù)需要使用人工創(chuàng)建并拋出。首先要生成異常類對象,然后通過throw語句實現(xiàn)拋出操作(提交給Java運 行環(huán)境)。
IOException e = new IOException();throw e;
可以拋出的異常必須是Throwable或其子類的實例。下面的語句在編譯時將 會產(chǎn)生語法錯誤:
throw new String("want to throw");

六、用戶自定義異常類

一般地,用戶自定義異常類都是RuntimeException的子類。自定義異常類通常需要編寫幾個重載的構造器。自定義異常需要提供serial VersionUID自定義異常通過throw拋出自定義異常最重要的是異常類的名字,當異常出現(xiàn)時,可以根據(jù)名字判斷異常類型。

用戶自定義異常類MyException,用于描述數(shù)據(jù)取值范圍錯誤信息。用戶 自己的異常類必須繼承現(xiàn)有的異常類。

public class MyException extends Exception {    static final long serialVersionUID = 1l;    private int idnumber;    public MyException(String message, int id) {        super(message);        this.idnumber = id;    }    public int getId() {        return idnumber;    }}
public class MyExpTest {    public void regist(int num) throws MyException {        if (num < 0) {            throw new MyException("人數(shù)為負值,不合理",3);        }else {            System.out.println("登記人數(shù)"+num);        }    }    public void manager(){        try {            regist(-1);        } catch (MyException e) {            e.printStackTrace();            System.out.println("登記失敗,出錯種類"+e.getId());        }    }    public static void main(String[] args) {        MyExpTest myExpTest = new MyExpTest();        myExpTest.manager();    }}

[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ jjwt-demo ---com.mink.jjwtdemo.mytest.exception.MyException: 人數(shù)為負值,不合理at com.mink.jjwtdemo.mytest.exception.MyExpTest.regist(MyExpTest.java:10)at com.mink.jjwtdemo.mytest.exception.MyExpTest.manager(MyExpTest.java:18)at com.mink.jjwtdemo.mytest.exception.MyExpTest.main(MyExpTest.java:27)登記失敗,出錯種類3

public class ReturnExceptionDemo {    static void methodA(){        try {            System.out.println("進入方法A");            throw new RuntimeException("制造異常");        } finally {            System.out.println("用A方法的finally");        }    }    static void methodB(){        try {            System.out.println("進入方法B");            return;        }finally {            System.out.println("用B方法的finally");        }    }    public static void main(String[] args) {        try {            methodA();        } catch (Exception e) {            e.printStackTrace();        }        methodB();    }}

[INFO] --- exec-maven-plugin:3.1.0:exec (default-cli) @ jjwt-demo ---進入方法A用A方法的finally進入方法B用B方法的finallyjava.lang.RuntimeException: 制造異常at com.mink.jjwtdemo.mytest.exception.ReturnExceptionDemo.methodA(ReturnExceptionDemo.java:11)at com.mink.jjwtdemo.mytest.exception.ReturnExceptionDemo.main(ReturnExceptionDemo.java:28)

package com.mink.jjwtdemo.mytest.exception.test;import sun.applet.Main;/** * @author Mink * @date 2022/10/21 10:59 * 編寫應用程序EcmDef.java,接收命令行的兩個參數(shù),要求不能輸入負數(shù),計算兩數(shù)相除。 *               對 數(shù) 據(jù) 類 型 不 一 致 (NumberFormatException) 、 *                缺 少 命 令 行 參 數(shù)(ArrayIndexOutOfBoundsException)、 *               除0(ArithmeticException) *               及輸入負數(shù)(EcDef 自定義的異常)進行異常處理。 * ?    提示: *  (1)在主類(EcmDef)中定義異常方法(ecm)完成兩數(shù)相除功能。 *  (2)在main()方法中使用異常處理語句進行異常處理。 *  (3)在程序中,自定義對應輸入負數(shù)的異常類(EcDef)。 *  (4)運行時接受參數(shù) java EcmDef 20 10 //args[0]=“20” args[1]=“10” *  (5)Interger類的static方法parseInt(String s)將s轉(zhuǎn)換成對應的int值。 *  如:int a=Interger.parseInt(“314”); //a=314; */public class EcmDef extends Throwable {    public static int ecm(int a, int b) throws EcDef{        if (a < 0 || b < 0){            throw new EcDef("分子或者分母為負數(shù)");        }        return a/b;    }    public static void main(String[] args) {        try {            int i = Integer.parseInt(args[0]);            int j = Integer.parseInt(args[1]);            int result = ecm(i,j);        }catch (NumberFormatException e){            e.printStackTrace();            System.out.println("數(shù)據(jù)類型不一致");        } catch (ArrayIndexOutOfBoundsException e){            System.out.println("下標越界,命令行缺少參數(shù)");        } catch (ArithmeticException e){            System.out.println("除 0");        } catch (EcDef e){            System.out.println("自定義異常");            System.out.println(e.getMessage());        }    }}class EcDef extends Exception{    static final long serialVersionUID = -12313131l;    public EcDef(String message) {        super(message);    }    public EcDef (){}}

標簽: 異常處理 自定義異常 拋出異常

上一篇:全球視訊!有關linux中的文件IO的操作
下一篇:世界信息:6.面向?qū)ο缶幊?下)