1. 程式人生 > 實用技巧 >java開發兩年!這些異常處理的方式你得知道,不然你憑什麼漲薪!

java開發兩年!這些異常處理的方式你得知道,不然你憑什麼漲薪!

前言

異常是在程式中導致程式中斷執行的一種指令流,當異常發生時,程式將直接中斷,不再執行後續的任何操作!
示例:兩數相除,若不處理任何異常,則只有在正確輸入兩個數字時,才能顯示出運算結果。

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("請輸入第1個數字:");
        String text1 = scanner.nextLine();
        int x1 = Integer.parseInt(text1);
        System.out.println("請輸入第2個數字:");
        String text2 = scanner.nextLine();
        int x2 = Integer.parseInt(text2);
        System.out.println(x1/x2);
    }

當輸入的內容不為數字時,就會產生異常(NumberFormatException,數字格式異常):

當輸入的內容均為數字,但除數為0時,也會產生異常(ArithmeticException,算數運算異常):

作為程式設計師,不要想當然的認為使用者一定會嚴格按照你的要求去輸入內容,如果他們某一步輸入出現錯誤,則整個程式都會中斷,所以一定要對異常進行處理!以下是異常處理後的程式碼:

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int x1;
        while (true) {
            System.out.println("請輸入第1個數字:");
            String text1 = scanner.nextLine();
            try {
                x1 = Integer.parseInt(text1);
                break;
            } catch (NumberFormatException e) {
                System.out.println("輸入有誤,請輸入數字!");
            }
        }
        int x2;
        while (true) {
            System.out.println("請輸入第2個數字:");
            String text2 = scanner.nextLine();
            try {
                x2 = Integer.parseInt(text2);
                break;
            } catch (NumberFormatException e) {
                System.out.println("輸入有誤,請輸入數字!");
            }
        }
        try {
            System.out.println(x1/x2);
        } catch (ArithmeticException e) {
            System.out.println("除數不能為0!");
        }
    }

當輸入的內容不為數字時,提示輸入有誤,並提示重新輸入:

當除數為0時,提示除數不能為0:

這,就叫異常處理。

try-catch

如果要想對異常進行處理,則必須採用標準的處理格式,處理格式語法如下:

try {
	// 有可能發生異常的程式碼段
} catch(異常型別1 物件名1) {
	// 異常的處理操作
} catch(異常型別2 物件名2) {
	// 異常的處理操作
} ...
finally {
	// 異常的統一出口
}

處理流程:

1.一旦產生異常,則系統會自動產生一個異常類的例項化物件;
2.那麼,此時如果異常發生在try語句,則會自動找到匹配的catch語句執行,如果沒有在try語句中,則會將異常丟擲;
3.所有的catch根據方法的引數匹配異常類的例項化物件,如果匹配成功,則表示由此catch進行處理,

finally:

在進行異常的處理之後,在異常的處理格式中還有一個finally語句,那麼此語句將作為異常的統一出口,不管是否產生了異常,最終都要執行此段程式碼。即使沒有發生異常,在try中使用了return語句,finally仍然會執行。

異常的體系結構

異常指的是Exception,Exception類,在Java中存在一個父類Throwable(可能的丟擲)
Throwable存在兩個子類:
1.Error:表示的是錯誤,是JVM發出的錯誤操作,只能儘量避免,無法用程式碼處理。
2.Exception:一般表示所有程式中的錯誤,所以一般在程式中將進行try…catch的處理。
其中Exception包括以下兩種,它們的處理方式相同:
1.受檢異常:
當程式寫好後,編譯器會自動對所寫程式碼進行檢測,如果有問題,程式碼將會飄紅線。
例如:SQLException、IOException、ClassNotFoundException等。
2.非受檢異常:
即執行時異常(RunntimeException),編譯器無法對所寫程式碼異常進行檢測,程式將在會在執行時報錯。
例如:NullPointException、ArithmethicException、ClassCastException、ArrayIndexOutOfBundException等。

多異常捕獲的注意點:

1.捕獲更粗的異常不能放在捕獲更細的異常之前。
2.如果為了方便,則可以將所有的異常都使用Exception進行捕獲。

特殊的多異常捕獲寫法:

catch(異常型別1 | 異常型別2 物件名) {
	//表示此塊用於處理異常型別1 和 異常型別2 的異常資訊
}

RuntimeExcepion與Exception的區別:

Integer類:public static int parseInt(String text)throws NumberFormatException
此方法丟擲了異常,但是使用時卻不需要進行try…catch捕獲處理,原因:
因為NumberFormatException並不是Exception的直接子類,而是RuntimeException的子類,只要是RuntimeException的子類,則表示程式在操作的時候可以不必使用try…catch進行處理(不飄紅線),如果有異常發生,則由JVM進行處理。當然,也可以通過try…catch處理。

throws關鍵字

在程式中異常的基本處理已經掌握了,但是隨異常一起的還有一個稱為throws關鍵字,此關鍵字主要在方法的宣告上使用,表示方法中不處理異常,而交給呼叫處處理。
格式:

返回值 方法名稱()throws Exception {
}

throw關鍵字

throw關鍵字表示在程式中人為的丟擲一個異常,因為從異常處理機制來看,所有的異常一旦產生之後,實際上丟擲的就是一個異常類的例項化物件,那麼此物件也可以由throw直接丟擲。
程式碼:

 throw new Exception("");

自定義異常類(瞭解)

編寫一個類,繼承Exception,並重寫一參構造方法,即可完成自定義受檢異常型別。
編寫一個類,繼承RuntimeExcepion,並重寫一參構造方法,即可完成自定義執行時異常型別。
例如:

class MyException extends Exception { // 繼承Exception,表示一個自定義異常類
	public MyException(String msg) {
		super(msg); // 呼叫Exception中有一個引數的構造
	}
}

自定義異常可以做很多事情, 例如:

class MyException extends Exception {
	public MyException(String msg) {
		super(msg);
		//在這裡給維護人員發簡訊或郵件, 告知程式出現了BUG。
	}
}

異常處理常見面試題

1.try-catch-finally中哪個部分可以省略?

答:catch和finally可以省略其中一個,catch和finally不能同時省略。
注意:格式上允許省略catch塊,但是發生異常時就不會捕獲異常了,在開發中也不會這樣去寫程式碼。

2.try-catch-finally中,如果catch中return了,finally還會執行嗎?

答:finally中的程式碼會執行。
執行流程:
1.先計算返回值,並將返回值儲存起來,等待返回;
2.執行finally程式碼塊;
3.將之前儲存的返回值返回出去。
需注意:
1.返回值是在finally運算之前就確定了,並且快取了,不管finally對該值做任何的改變,返回的值都不會改變。
2.finally程式碼中不建議包含return,因為程式會在上述的流程中提前退出,也就是說返回的值不是try或catch中的值。
3.如果在try或catch中停止了JVM,則finally不會執行。例如停電,或通過如下程式碼退出:
JVM:System.exit(0);

3.關於以下程式碼的輸出:

public class Student {
    public static void main(String[] args) {
        int studentId = test();
        System.out.println("學生的學號是"+studentId);
    }
    public static int test() {
        int studentId = 1000;
        try {
            return studentId;
        } catch(Exception e) {
            return 0;
        } finally {
            studentId=10;
        }
    }
}

正確答案是:學生的學號是1000
解:首先studentId是1000,然後執行到try,將要return學號,此時會對基本資料型別變數studentId的值1000進行備份,然後執行finally,studentId變為10,但是這隻改變了原有變數的值,備份的值不會發生變化,最終return的仍然是曾經的備份值,即1000。

4.和上題類似的案例:

public class Student {
    public static void main(String[] args) {
        StudentId s = test();
        System.out.println("學生的學號是"+s.studentId);
    }
    public static StudentId test() {
        StudentId s = new StudentId();
        s.studentId = 1000;
        try {
            return s;
        } catch(Exception e) {
            return s;
        } finally {
            s.studentId=10;
        }
    }
    public static class StudentId {
        int studentId;
    }
}

正確答案是:學生的學號是10
解:首先棧記憶體中的s儲存了堆記憶體的地址,堆記憶體中s.studentId初始為1000,然後執行到try,將要return的是堆記憶體的地址,此時會對地址進行備份,然後執行finally,堆記憶體中s.studentId改為10,最終備份的地址被return出去,但實際上地址始終沒有發生過變化,s.studentId的值即為修改後的10。

最後

感謝你看到這裡,文章有什麼不足還請指正,覺得文章對你有幫助的話記得給我點個贊,每天都會分享java相關技術文章或行業資訊,歡迎大家關注和轉發文章!