java面向物件-6(異常)
java面向物件-6
異常定義和分類
異常機制是程式執行出現問題後,程式的處理機制。可理解為正常程式執行出現問題後的PlanB
程式錯誤分為三種:編譯異常、執行異常和邏輯錯誤。
(1)編譯異常是因為程式沒有遵循語法規則,編譯程式能夠自己發現並且提示我們異常的原因和位置
(2)執行時異常是因為程式在執行時,執行環境發現了不能執行的操作。
(3)邏輯錯誤是因為程式沒有按照預期的邏輯順序執行。異常也就是指程式執行時發生錯誤,而異常處理就是對這些錯誤進行處理和控制。
執行異常的父類是RuntimeException,RuntimeException的父類是Exception,Exception的父類是Throwable
異常的處理
try…catch
/*try...catch即為捕獲要發生的異常
若異常未發生,按照try程式碼塊執行,若異常發生了,則按照catch程式碼塊執行
邏輯類似於if*/
public static void main(String[] args){
try{
//會先執行try程式碼塊,在異常出現之前的程式碼可以執行到;
System.out.println("進入try程式碼塊");
int a=1/0;
System.out.println("出現異常,本行程式碼無法被執行");
}catch( ArithmeticException ae) {
System.out.println("捕獲到異常,進入catch程式碼塊");
//列印全部的異常資訊,JVM處理異常時也是呼叫此方法
ae.printStackTrace();
//列印異常原因,但是不會有異常型別和問題程式碼定位
System.out.println(ae.getMessage());
}
System.out.println("因為異常被捕獲,本行程式碼可以執行");
}
執行結果:
可以看到,程式順利結束(產生異常結束時,exit cot 1)
printStackTrace()方法列印格式錯亂的原因:當執行到產生異常的程式碼時,會新開一個執行緒去繼續執行程式碼,原執行緒列印錯誤資訊,執行緒列印資訊不具有原子性,可以多嘗試幾次,格式錯亂的結果會不一樣
public static void main(String[] args){
try{
System.out.println("進入try程式碼塊");
int a=1/0;
System.out.println("出現異常,本行程式碼無法被執行");
}catch( ArithmeticException ae){
System.out.println("捕獲到異常,進入catch程式碼塊");
ae.printStackTrace();
System.out.println(ae.getMessage());
}finally{//上面部分還是一樣的
//finally程式碼塊無論是否發生了異常都會執行
System.out.println("進入finally程式碼塊");//本行語句一定會輸出
}
System.out.println("因為異常被捕獲,本行程式碼可以執行");
}
//當try...catch...finally被定義在方法中時
private static void method(){
try{
System.out.println(1);
System.out.println(1/0);
}catch (ArithmeticException ae){
System.out.println(2);
/*特別注意這裡,發生了異常,在catch程式碼塊中執行到了return,
但是方法不會立刻結束,仍會執行finally程式碼塊,執行完畢後結束方法*/
return;
}finally {
System.out.println(3);
}
}
//呼叫本方法輸出結果為:1 2 3
//當方法有返回值的時候
private static int method(){
int i=0;
try{
i++;
i=1/0;
i++;
}catch (ArithmeticException ae){
/*當執行到這裡時,會返回i+1=2,將值返回後,
仍會執行finally,i值變為3,但是不會重複返回*/
return ++i;
}finally {
i++;
}
return i;//本行程式碼不會被執行到
}
//呼叫本方法輸出結果為:2
private static int method(){
int i=0;
try{
i++;
i=1/0;
i++;
}catch (ArithmeticException ae){
return ++i;
}finally {
i++;
/*雖然catch程式碼塊返回了數值2,但是仍會執行finally程式碼塊
而finally程式碼塊中也會返回一次,會覆蓋上次返回結果*/
return i;
}
}
//呼叫本方法輸出結果為:3
/*結論:
在try-catch-finally結構中,會先進入try程式碼塊執行,
如果沒有發生異常,就會執行try和finally程式碼塊的內容後結束;
如果發生了異常就會執行try中發生異常前的部分,catch和finally程式碼塊後結束;
當執行過程中,遇到return語句時,仍會繼續執行finally程式碼塊;
可理解為執行到return時先將結果返回,再去執行finally程式碼塊,除非finally
程式碼塊中也有return覆蓋原有結果,否則執行finally程式碼塊不影響返回的結果,
這是因為方法返回基本數值時並非返回該變數,而是返回數值本身,如果返回值是
引用資料型別,返回結果會保留方法最後一次操作的結果(結果類似遞迴)
例外情況:當執行到System.exit()時,程式會強制結束,finally將不再執行;
*/
throws
丟擲異常,throws的作用是將異常丟擲,交給呼叫者去處理
異常可以層層向上丟擲,由產生異常的方法拋給方法的呼叫者,方法呼叫者可以選擇try-catch解決異常,也可以繼續丟擲,直到拋給main方法
main方法中的異常最好使用try-catch解決掉,因為此時在throws丟擲會將異常拋給JVM處理,異常發生則會中斷程式
throws使用格式:
//可以同時丟擲多個異常,中間使用逗號隔開
//也可以丟擲一個大異常,同時cover多個異常
public static void method()throws FileNotFoundException,ArithmeticException{
int i=1/0;
FileInputStream fis=new FileInputStream("");
}
自定義異常
定義步驟:
1、建立一個類,類名命名為想要建立的異常的名字
2、繼承RuntimeException、Exception或者Throwable類,如果希望 編譯期報錯,則繼承Exception,希望執行期報錯,則繼承RuntimeException
3、定義構造方法,引數列表為異常提示資訊,使用super關鍵字呼叫父類構造方法,傳入異常提示資訊
自定義異常類建立過程(以RuntimeException子類為例):
public class AgeException extends RuntimeException{
public AgeException(String message){
super(message);//傳入異常提示資訊
}
}
//在Exception和RuntimeException中也是層層呼叫父類構造方法建立異常的
public RuntimeException(String message) {
super(message);
}
public Exception(String message) {
super(message);
}
//在Throwable類中定義了異常資訊屬性
private String detailMessage;
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;//最終異常資訊會傳遞到這裡,交由detailMessage屬性儲存
}
//當呼叫printStackTrace和getMessage時則會將detailMessage輸出和返回
public String getMessage() {
return detailMessage;
}