欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java高效利用異常處理的技巧總結(jié)

 更新時間:2023年09月05日 16:37:05   作者:碼農(nóng)高飛  
這篇文章主要為大家詳細介紹了Java如何高效利用異常處理,從而達到優(yōu)化代碼的效果,文中的示例代碼講解詳細,感興趣的小伙伴可以學(xué)習(xí)一下

概述

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

那么在程序執(zhí)行過程中,出現(xiàn)的非正常情況,如果不處理最終會導(dǎo)致JVM的非正常停止,這就是異常。

異常指的并不是語法錯誤和邏輯錯誤,語法錯了編譯不會通過,不會產(chǎn)生字節(jié)碼文件,根本不能運行。而代碼邏輯錯誤,只是沒有得到想要的結(jié)果。

Java中把不同的異常用不同的類表示,一旦發(fā)生某種異常,就創(chuàng)建該異常類型的對象并且拋出(throw),然后程序員可以catch到這個異常對象并處理,如果無法catch到異常對象,那么這個異常對象將會導(dǎo)致程序的終止。

所以在編寫程序時,就應(yīng)該充分考慮到各種可能發(fā)生的異常和錯誤,極力的預(yù)防和避免,實在無法避免的,也要編寫相應(yīng)的代碼進行異常的檢測、以及處理,從而保證代碼的健壯性。

Java異常體系

Error和Exception

Java程序在執(zhí)行過程中所發(fā)生的異常事件可分為兩類:Error和Exception,分別對應(yīng)著java.lang.Errorjava.lang.Exception兩個類。

Error是Java虛擬機無法解決的嚴(yán)重問題,如JVM系統(tǒng)內(nèi)部錯誤、資源耗盡等嚴(yán)重情況,一般不編寫針對性的代碼進行處理。

Exception是因編程錯誤或偶然的外在因素導(dǎo)致的一般性問題,可以使用針對性的代碼進行處理,使程序繼續(xù)運行,但只要發(fā)生必須處理,否則程序也會終止,例如:

  • 空指針訪問
  • 試圖讀取不存在的文件
  • 網(wǎng)絡(luò)連接中斷
  • 數(shù)組角標(biāo)越界

無論是Error還是Exception,還有很多子類,異常的類型非常豐富,當(dāng)代碼運行出現(xiàn)異常時,特別是不熟悉的異常時,可以在API中通過異常的類名去查詢。

提示: 平時說的異常就是指Exception。

Throwable

java.lang.Throwable類是Error和Exception的父類。只有當(dāng)對象是此類(或其子類之一)的實例時,才能通過Java虛擬機或Java的throw語句拋出,同樣的只有此類或其子類之一才可以是catch子句中的參數(shù)類型。

Throwable中的常用方法:

  • public void printStackTrace():打印異常的詳細信息,包含了異常的類型、原因和出現(xiàn)的位置,在開發(fā)和調(diào)試階段都得使用printStackTrace。
  • public String getMessage():獲取發(fā)生異常的原因,提示給用戶的時候就提示錯誤的原因。

常見的錯誤和異常

對于程序出現(xiàn)的異常,一般有兩種,一是遇到錯誤就終止程序的運行,另一種是由程序員在編寫程序時,就考慮到錯誤的檢測、錯誤消息的提示,以及錯誤的處理。

最理想的捕獲異常是在編譯期間,但有的錯誤只有在運行時才會發(fā)生,比如數(shù)組下標(biāo)越界等。因此根據(jù)代碼的執(zhí)行階段,編譯器是否會警示當(dāng)前代碼可能發(fā)生異常,并督促程序員提前編寫處理它的代碼為依據(jù),可以將異常分為編譯時異常和運行時異常。

編譯時異常

編譯時異常(checked異常、受檢異常):在代碼編譯階段,編譯器就能明確警示當(dāng)前代碼可能發(fā)生但不一定發(fā)生的異常,并明確督促提前編寫處理代碼,如果沒有編寫相應(yīng)的異常處理代碼,則編譯器就直接判定編譯失敗,從而導(dǎo)致程序無法執(zhí)行,通常這類異常的發(fā)生不是由編寫的代碼引起的,或不是靠加簡單判斷可以避免的。

示例:

import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class TestCheckedException {
    @Test
    public void test01() {
        Thread.sleep(1000); //休眠1秒,InterruptedException
    }
    @Test
    public void test02(){
        Class c = Class.forName("java.lang.String"); //ClassNotFoundException
    }
    @Test
    public void test03() {
        Connection conn = DriverManager.getConnection("xxx");  //SQLException
    }
    @Test
    public void test04()  {
        FileInputStream fis = new FileInputStream("xxx.txt"); //FileNotFoundException
    }
    @Test
    public void test5() {
        File file = new File("xxx.txt");
		FileInputStream fis = new FileInputStream(file); //FileNotFoundException
		int b = fis.read(); //IOException
		while(b != -1){
			System.out.print((char)b);
			b = fis.read(); //IOException
		}
		fis.close(); //IOException
    }
}

運行時異常

運行時異常(runtime異常、unchecked異常、非受檢異常):在代碼編譯階段,編譯器完全不做任何的檢查,無論該異常是否會發(fā)生,編譯器都不給出任何提示。只有等代碼運行起來并確定發(fā)生了異常才能被發(fā)現(xiàn),通常這類異常是由程序員的代碼編寫不當(dāng)引起的,只要稍加判斷或細心檢查就可以避免。

示例:

import org.junit.Test;
import java.util.Scanner;
public class TestRuntimeException {
    @Test
    public void test01(){
        //NullPointerException
        int[][] arr = new int[3][];
        System.out.println(arr[0].length);
    }
    @Test
    public void test02(){
        //ClassCastException
        Object obj = 15;
        String str = (String) obj;
    }
    @Test
    public void test03(){
        //ArrayIndexOutOfBoundsException
        int[] arr = new int[5];
        for (int i = 1; i <= 5; i++) {
            System.out.println(arr[i]);
        }
    }
    @Test
    public void test04(){
        //InputMismatchException
        Scanner input = new Scanner(System.in);
        System.out.print("請輸入一個整數(shù):"); //輸入非整數(shù)
        int num = input.nextInt();
        input.close();
    }
    @Test
    public void test05(){
        int a = 1;
        int b = 0;
        //ArithmeticException
        System.out.println(a/b);
    }
}

Error

最常見的就是VirtualMachineError,有兩個經(jīng)典的子類:StackOverflowError、OutOfMemoryError。

示例:

import org.junit.Test;
public class TestError {
    //StackOverflowError
    @Test
    public void test01(){
        recursion();
    }
    public void recursion(){ //遞歸方法
        recursion(); 
    }
    //OutOfMemoryError
    @Test
    public void test02(){
        int[] arr = new int[Integer.MAX_VALUE]; //方式一
    }
    @Test
    public void test03(){
        StringBuilder s = new StringBuilder(); //方式二
        while(true){
            s.append("xxx");
        }
    }
}

異常的處理

在編寫程序時,經(jīng)常要在可能出現(xiàn)錯誤的地方加上檢測的代碼,如進行除法運算時,需要檢測分母是否為0等,這樣一來會出現(xiàn)過多的if-else分支,導(dǎo)致程序的代碼加長、臃腫,可讀性差,程序員需要花很大的精力去堵漏洞,因此采用異常處理機制。

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

Java異常處理的方式有兩種,一種是try-catch-finally,另一種是throws+異常類型。

捕獲異常

Java提供了異常處理的抓拋模型,之前提到Java程序的執(zhí)行過程中如果出現(xiàn)異常,會生成一個異常類對象,該異常對象將被提交給Java運行時系統(tǒng),這個過程稱為拋出異常。

如果一個方法內(nèi)拋出異常,該異常對象會被拋給調(diào)用者方法中處理,如果異常沒有在調(diào)用者方法中處理,它繼續(xù)被拋給這個調(diào)用方法的上層方法,這個過程將一直繼續(xù)下去,直到異常被處理,這個過程稱為捕獲異常。

如果一個異常回到main方法,并且main方法不處理,則程序終止。

捕獲異常的語法如下:

try{
	...... //可能產(chǎn)生異常的代碼
}
catch( 異常類型1 e ){
	...... //當(dāng)產(chǎn)生ExceptionName1類型異常時的處理
}
catch( 異常類型2 e ){
	...... //當(dāng)產(chǎn)生ExceptionName2類型異常時的處理
}  
[finally{
	...... //無論是否發(fā)生異常,都無條件執(zhí)行的代碼
}]

當(dāng)某段代碼可能發(fā)生異常時,不管此異常是編譯時異常還是運行時異常,都可以使用try塊括起來,并在try塊下面編寫catch分支捕獲對應(yīng)的異常對象。

  • 如果在程序運行時,try中代碼沒有發(fā)生異常,則catch中代碼不執(zhí)行
  • 如果在程序運行時,try中代碼發(fā)生了異常,則根據(jù)異常的類型從上到下選擇第一個匹配的catch分支執(zhí)行,此時try中發(fā)生異常的語句下面的代碼將不執(zhí)行,整個try-catch之后的代碼可以繼續(xù)執(zhí)行
  • 如果在程序運行時,try中代碼發(fā)生了異常,但所有的catch分支都無法匹配這個異常,那么JVM將會終止當(dāng)前方法的執(zhí)行,并把異常對象拋給調(diào)用者,如果調(diào)用者也不處理,那么程序就掛了

注意: 當(dāng)有多個catch分支時,且多個異常類型有父子類關(guān)系,必須保證小的子異常類型在上,大的父異常類型在下。

示例:

import java.util.InputMismatchException;
import java.util.Scanner;
public class TestTryCatch {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.print("請輸入第一個整數(shù):");
            int a = input.nextInt();
            System.out.print("請輸入第二個整數(shù):");
            int b = input.nextInt();
            int result = a/b;
            System.out.println(a + "/" + b +"=" + result);
        } catch (InputMismatchException e) {
            System.out.println("數(shù)字格式不正確,請輸入兩個整數(shù)");
        }catch (ArithmeticException e){
            System.out.println("第二個整數(shù)不能為0");
        } finally {
            System.out.println("程序結(jié)束,釋放資源");
            input.close();
        }
    }
}

catch捕獲異常的信息,與其它對象一樣,可以訪問一個異常對象的成員變量或調(diào)用它的方法,為此Throwable類中定義了一些查看方法,比如有:

  • public String getMessage():獲取異常的描述信息,返回字符串
  • public void printStackTrace():打印異常的跟蹤棧信息并輸出到控制臺,包含異常的類型、原因和出現(xiàn)的位置,在開發(fā)和調(diào)試階段都得使用printStackTrace

示例:

@Test
public void test1(){
	FileInputStream fis = null;
	try{
		File file = new File("xxx.txt");
		fis = new FileInputStream(file); //FileNotFoundException
		int b = fis.read(); //IOException
		while(b != -1){
			System.out.print((char)b);
			b = fis.read(); //IOException
		}
	}catch(IOException e){
		e.printStackTrace();
	}finally{
		try {
			if(fis != null)
				fis.close(); //IOException
		} catch (IOException e) {
			e.printStackTrace();
		}	
	}
}

如果多個catch分支的異常處理代碼一致,在JDK1.7之后還支持以下寫法:

try{
     可能發(fā)生異常的代碼
}catch(異常類型1 | 異常類型2  e){
     處理異常的代碼1
}catch(異常類型3  e){
     處理異常的代碼2
}
....

最后,這些異常都是運行時異常類或它的子類,這些異常類的特點是即使沒有使用try-catch,Java也能捕獲并且編譯通過。如果拋出的異常是IOException等類型的非運行時異常,則必須捕獲,否則編譯錯誤,所以必須處理編譯時異常,將異常進行捕獲轉(zhuǎn)化為運行時異常。

聲明拋出異常類型

如果一個方法可能生成某種異常,但并不能確定如何處理這種異常,則此方法應(yīng)顯示的聲明拋出異常,表明該方法將不對這些異常進行處理,而由該方法的調(diào)用者負責(zé)處理。在方法聲明中用throws語句可以聲明拋出異常的列表,throws后面的異常類型可以是方法中產(chǎn)生的異常類型,也可以是它的父類。

throws聲明異常格式如下:

修飾符 返回值類型 方法名(參數(shù)) throws 異常類名1,異常類名2…{   }    

在throws后面可以寫多個異常類型,用逗號隔開。

示例:

public void readFile(String file)  throws FileNotFoundException {
	...
	//讀文件的操作可能產(chǎn)生FileNotFoundException類型的異常
	FileInputStream fis = new FileInputStream(file);
	...
}

throws編譯時異常:

如果在編寫方法體代碼時,某代碼可能發(fā)生某個編譯時異常,不處理編譯不通過,但在當(dāng)前方法體中可能不適合處理或無法給出合理的處理方式,就可以通過throws在方法簽名中聲明該方法可能會發(fā)生異常,需要調(diào)用者處理。

示例:

public class TestThrowsCheckedException {
    public static void main(String[] args) {
        System.out.println("xxxxxx");
        try {
            afterClass(); //換到這里處理異常
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("XXXXXX");
        }
        System.out.println("......");
    }
    public static void afterClass() throws InterruptedException {
        for(int i=10; i>=1; i--){
            Thread.sleep(1000); //本來應(yīng)該在這里處理異常
            System.out.println("xxxxxx" + i);
        }
    }
}

throws運行時異常:

throws后面也可以寫運行時異常類型,只是運行時異常類型寫或不寫對于編譯器和程序執(zhí)行來說都沒有任何區(qū)別,如果寫了,唯一的區(qū)別就是調(diào)用者調(diào)用該方法后使用try-catch結(jié)構(gòu)時,idea可以獲得更多的信息,需要添加哪種catch分支。

示例:

import java.util.InputMismatchException;
import java.util.Scanner;
public class TestThrowsRuntimeException {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        try {
            System.out.print("請輸入第一個整數(shù):");
            int a = input.nextInt();
            System.out.print("請輸入第二個整數(shù):");
            int b = input.nextInt();
            int result = divide(a,b);
            System.out.println(a + "/" + b +"=" + result);
        } catch (ArithmeticException | InputMismatchException e) {
            e.printStackTrace();
        } finally {
            input.close();
        }
    }
    public static int divide(int a, int b)throws ArithmeticException{
        return a/b;
    }
}

方法重寫對于throws的要求:

方法重寫時,對于方法簽名是有嚴(yán)格要求的,比如:

  • 方法名必須相同
  • 形參列表必須相同
  • 返回值類型:基本數(shù)據(jù)類型和void必須相同;引用數(shù)據(jù)類型要<=
  • 權(quán)限修飾符:>=,而且要求父類被重寫方法在子類中是可見的
  • 不能是static、final修飾的方法

此外,對于throws異常列表要求:

  • 如果父類被重寫方法的方法簽名后沒有throws編譯時異常類型,那么重寫方法時,方法簽名后面也不能出現(xiàn)throws編譯時異常類型
  • 如果父類被重寫方法的方法簽名后面有throws 編譯時異常類型,那么重寫方法時throws的編譯時異常類型必須<=被重寫方法throws的編譯時異常類型,或者不throws編譯時異常
  • 方法重寫對于throws 運行時異常類型沒有要求

示例:

import java.io.IOException;
class Father{
    public void method()throws Exception{
        System.out.println("Father.method");
    }
}
class Son extends Father{
    @Override
    public void method() throws IOException,ClassCastException {
        System.out.println("Son.method");
    }
}

手動拋出異常對象:throw

Java中異常對象的生成有兩種方式:

  • 由虛擬機自動生成:程序運行過程中,虛擬機檢測到程序發(fā)生了問題,針對當(dāng)前代碼就會在后臺自動創(chuàng)建一個對應(yīng)異常類的實例對象并拋出
  • 由開發(fā)人員手動創(chuàng)建:new 異常類型([實參列表]),如果創(chuàng)建好的異常對象不拋出對程序沒有任何影響,和創(chuàng)建一個普通對象一樣,但一旦throw拋出,就會對程序運行產(chǎn)生影響了

語法格式

使用格式如下:

throw new 異常類名(參數(shù));

throw語句拋出的異常對象和JVM自動創(chuàng)建和拋出的異常對象一樣:

  • 如果是編譯時異常類型的對象,同樣需要使用throws或try-catch處理,否則編譯不通過
  • 如果是運行時異常類型的對象,編譯器不提示
  • 可以拋出的異常必須是Throwable或其子類的實例
//編譯時會產(chǎn)生語法錯誤
throw new String("want to throw");

注意事項

無論是編譯時異常類型的對象還是運行時異常類型的對象,如果沒有被try-catch合理的處理,都會導(dǎo)致程序的崩潰。

throw語句會導(dǎo)致程序執(zhí)行流程被改變,throw語句是明確拋出一個異常對象,因此它下面的代碼將不會執(zhí)行。

如果當(dāng)前方法沒有try-catch處理這個異常對象,throw語句就會代替return語句提前終止當(dāng)前方法的執(zhí)行,并返回一個異常對象給調(diào)用者。

示例:

public class TestThrow {
    public static void main(String[] args) {
        try {
            System.out.println(max(4,2,31,1));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            System.out.println(max(4));
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            System.out.println(max());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static int max(int... nums){
        if(nums == null || nums.length==0){
            throw new IllegalArgumentException("沒有傳入任何整數(shù),無法獲取最大值");
        }
        int max = nums[0];
        for (int i = 1; i < nums.length; i++) {
            if(nums[i] > max){
                max = nums[i];
            }
        }
        return max;
    }
}

自定義異常

為什么需要自定義異常類

Java中不同的異常類分別表示著某一種具體的異常情況,那么在開發(fā)中總是有些異常情況是核心類庫中沒有定義好的,此時就需要根據(jù)自己的業(yè)務(wù)異常情況來定義異常類。

如何自定義異常類

要繼承一個異常類型。

  • 自定義一個編譯時異常類型:自定義類繼承java.lang.Exception
  • 自定義一個運行時異常類型:自定義類繼承java.lang.RuntimeException

建議提供至少兩個構(gòu)造器,一個是無參構(gòu)造器一個是(String message)構(gòu)造器。

自定義異常需要提供serialVersionUID

注意:

自定義的異常只能通過throw拋出。

自定義異常最重要的是異常類的名字和message屬性,當(dāng)異常出現(xiàn)時可以根據(jù)名字判斷異常類型。

自定義異常對象只能手動拋出,拋出后由try-catch處理,也可以甩鍋throws給調(diào)用者處理。

示例:

//自定義異常類
class MyException extends Exception {
    static final long serialVersionUID = 23423423435L;
    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(100);
        } catch (MyException e) {
            System.out.print("登記失敗,出錯種類" + e.getId());
        }
        System.out.print("本次登記操作結(jié)束");
    }
    public static void main(String args[]) {
        MyExpTest t = new MyExpTest();
        t.manager();
    }
}

小結(jié)

異常處理的5個關(guān)鍵字:

到此這篇關(guān)于Java高效利用異常處理的技巧總結(jié)的文章就介紹到這了,更多相關(guān)Java異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Jmeter生成UUID作為唯一標(biāo)識符過程圖解

    Jmeter生成UUID作為唯一標(biāo)識符過程圖解

    這篇文章主要介紹了Jmeter生成UUID作為唯一標(biāo)識符過程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • java ArrayList和Vector的區(qū)別詳解

    java ArrayList和Vector的區(qū)別詳解

    這篇文章主要介紹了java ArrayList和Vector的區(qū)別詳解的相關(guān)資料,并附簡單實例代碼,需要的朋友可以參考下
    2016-11-11
  • SpringBoot2 整合MinIO中間件實現(xiàn)文件便捷管理功能

    SpringBoot2 整合MinIO中間件實現(xiàn)文件便捷管理功能

    這篇文章主要介紹了SpringBoot2 整合MinIO中間件,實現(xiàn)文件便捷管理,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • 在Java的Hibernate框架中使用SQL語句的簡單介紹

    在Java的Hibernate框架中使用SQL語句的簡單介紹

    這篇文章主要介紹了在Java的Hibernate框架中使用SQL語句的方法,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下
    2016-01-01
  • SpringBoot之如何指定配置文件啟動

    SpringBoot之如何指定配置文件啟動

    這篇文章主要介紹了SpringBoot之如何指定配置文件啟動問題,具有很好的參考價值,希望對大家有所幫助。
    2023-04-04
  • Java實現(xiàn)學(xué)生管理系統(tǒng)(控制臺版本)

    Java實現(xiàn)學(xué)生管理系統(tǒng)(控制臺版本)

    這篇文章主要為大家詳細介紹了如何利用Java語言實現(xiàn)控制臺版本的學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 8種常見的接口請求重試方法總結(jié)

    8種常見的接口請求重試方法總結(jié)

    在跨境業(yè)務(wù)中,可能第三方的服務(wù)器分布在世界的各個角落,所以請求三方接口的時候,難免會遇到一些網(wǎng)絡(luò)問題,這時候需要加入重試機制了,下面小編就給大家分享幾個接口重試的寫法吧
    2023-11-11
  • Java中比較Long類型是否相等代碼示例

    Java中比較Long類型是否相等代碼示例

    在Java編程中l(wèi)ong是一種數(shù)據(jù)類型,用于表示整數(shù)值,下面這篇文章主要給大家介紹了關(guān)于Java中比較Long類型是否相等的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-05-05
  • java接口類中的@selectProvider接口的使用及說明

    java接口類中的@selectProvider接口的使用及說明

    這篇文章主要介紹了java接口類中的@selectProvider接口的使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • java中的stream流中的并行查詢java

    java中的stream流中的并行查詢java

    Stream流是Java 8引入的一種新的數(shù)據(jù)處理方式,它提供了一種高效、簡潔的數(shù)據(jù)處理方式,Stream流可以讓我們以聲明式的方式處理數(shù)據(jù),提高了代碼的可讀性和可維護性,同時,Stream流支持并行處理,可以充分利用多核CPU的性能,提高程序的運行效率
    2024-07-07

最新評論