1. 程式人生 > 其它 >異常-Java學習日記

異常-Java學習日記

異常:就是程式不正常的情況
ava中程式的異常:Throwable
Error:嚴重的問題,這樣的情況,我們一般不做處理,因為這樣的問題一般不是程式本身帶來問題,而是外界導致。
Exception:
編譯時期異常:除了RuntimeException以外的異常都是編譯時期異常,這樣的異常必須做處理,
如果不處理程式無法執行,編譯無法通過
執行時期異常:RuntimeException 這樣的 問題我們可以不做處理,因為這是你自己的問題,通常情況下,出現這樣的問題一般都是
因為程式碼的邏輯不夠嚴謹導致的。
出現問題後,如果我們沒有做任何處理,JVM會提供一個預設的處理方式,可以看到出現了什麼異常,出現異常的資訊,以及出現問題的程式碼行

 

public class ExceptionDemo1 {
    public static void main(String[] args) {
        //執行時期異常
        int[] arr = {11,22,33,44,55};
        System.out.println(arr[1]);
        System.out.println(arr[5]);
    
        System.out.println("hello");

    }
}
/*
    執行結果
    22
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
        at com.shujia.lc.day22.ketang.ExceptionDemo1.main(ExceptionDemo1.java:27)
 
*/

 

異常處理方案
1try…catch…finally
2throws

try…catch…finally處理格式:
try{
可能會出現問題的程式碼;
}catch(異常的類名 變數名){
針對出現的問題做處理;
}finally{
一般情況下,這裡寫釋放資源;
}
變形格式:
try{
可能會出現問題的程式碼;
}catch(異常的類名 變數名){
針對出現的問題做處理;
}
注意:
1try裡面的程式碼如果出現問題,try裡面的程式碼就會停在那一行,然後JVM會自動識別是什麼問題,去catch匹配對應的異常,匹配到後
執行對應的處理方式(catch大括號中的程式碼),如果沒有匹配到,JVM會執行預設的處理方式,而預設的處理方式會將程式停止,後面的程式碼都不會執行
2try裡面的程式碼越少越好,確定不會出錯的程式碼就不要try裡面寫了。
3catch裡面必須要有內容,哪怕就寫了一個簡單輸出語句提示

 

public class ExceptionDemo2 {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        try {
            System.out.println(a / b);

        } catch (ArithmeticException ae) {
            System.out.println("你的除數為0了");
        }

        System.out.println("world");
        System.out.println("hello");

    }
}
/*
    執行結果
    你的除數為0了
    world
    hello
 */

 

處理一個異常和處理多個異常
處理多個異常的方案:
1、對每一個異常都寫一個try...catch...
2、寫一個try,多個catch
try{
...
}catch(){
...
}catch(){
...
}
注意事項:
1、多個異常使用try..catch處理的時候,catch可以寫一個,裡面寫最大的父類Exception,但是如果這麼寫了,try裡面
無論出現什麼錯誤,都會匹配到這裡的catch,這樣的做的話,所有的問題處理方式都是一種處理,沒法區分,不推薦這麼做
2、多個catch之間可以是繼承關係,但是,要把父類的catch寫在最後,因為出現問題匹配catch的順序是自上而下的。
3JDK1.7之後出現了處理異常的新方案:
try{
放上可能會出現問題的程式碼;
}catch(異常類名1|異常類名2|異常類名3|... 變數名){
處理問題的程式碼;
}
注意:
1)新特性處理的方式並不太好,因為多種異常的處理方式統一是一種
2)新特性的處理catch中的異常只能是平級關係,不能是繼承關係

 

public class ExceptionDemo3 {
    public static void main(String[] args) {
        //編譯時期異常
        String s = "2022-04-06 14:35:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        try {
//            Date date = sdf.parse(s);
//            System.out.println(date);
//        }catch (ParseException pe){
//            System.out.println("日期轉換出錯了!!!");
//        }
//
//        int[] arr = {11,22,33,44,55};
//        try {
//            System.out.println(arr[5]);
//        }catch (ArrayIndexOutOfBoundsException aiob){
//            System.out.println("取了不該取的索引");
//        }
        System.out.println("===============================================");
        //第二種處理方式:寫一個try,多個catch

//        try {
//            Date date = sdf.parse(s);
//            int[] arr = {11, 22, 33, 44, 55};
//            System.out.println(arr[5]);
//        }catch (ParseException ae){
//            System.out.println("日期處理格式");
//        }catch (Exception ae){
//            System.out.println("取了不該取的索引");
//        }
        System.out.println("===============================================");
        //JDK1.7try..catch處理新方式
        try {
            Date date = sdf.parse(s);
            int[] arr = {11, 22, 33, 44, 55};
            System.out.println(arr[5]);
        }catch (ParseException|ArrayIndexOutOfBoundsException e){
            System.out.println("出錯啦!!");
        }

        System.out.println("你好!!!");

    }
}

 

在前面案例中,我們處理異常的方式都是輸出一句話,告訴我們出了什麼問題,但是呢,對比發現,並沒有預設處理方式來的直接和清楚
try..catch..的處理過程是,當try中的程式碼出現了問題的時候,JVM會幫助我們生成一個異常物件,然後把這個物件跑出來,與catch中的
型別進行匹配,如果匹配到了,就走對應的處理方式。

異常中需要了解的幾個方法:
1getMessage()
獲取異常資訊,返回字串。
2toString()
獲取異常類名和異常資訊,返回字串。
3printStackTrace()
獲取異常類名和異常資訊,以及異常出現在程式中的位置。返回值void

 

public class ExceptionDemo4 {
    public static void main(String[] args) {
        String s = "2020-04-06";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        try {
//            Date date = sdf.parse(s);
//            System.out.println(date);
//        }catch (ParseException pe){ // ParseException pe = new ParseException();
////            System.out.println("日期轉換異常");
////            String message = pe.getMessage();
////            System.out.println(message);
//
////            String s1 = pe.toString();
////            //此物件的類的name(全路徑名)
////            //": "(冒號和一個空格)
////            //呼叫此物件中的getLocalizedMessage()方法,底層呼叫的還是getMessage()方法。
////            System.out.println(s1);
//
//            pe.printStackTrace();
//        }

        try {
            Date date = sdf.parse(s);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        System.out.println("你好!!");

    }
}

 

有些時候,我們可以對異常去做處理,但是呢,有些時候,我們根本就沒有許可權去處理這些異常。
或者說, 我們處理不了,就不處理了,交給更高許可權的去處理。
為了解決這樣出錯的問題,Java針對這種情況,就提供了另一種處理方案:丟擲

格式:
throws 異常類名
注意:這個格式必須跟在方法的小括號後面,大括號前面。
注意:
1、儘量不要在main方法上面丟擲,因為main方法是由JVM呼叫的,如果出問題了,依舊是走預設的處理方式,
而預設的處理方式,會將程式終止,後續程式碼不會執行,推薦能try..catchtry..catch
(為了上課方便,後面的課程我就大部分在方法上丟擲了)
2、編譯時期異常丟擲,呼叫者必須要做處理,因為不做就沒辦法通過編譯,就無法執行
3、執行時期異常丟擲,呼叫者可以不做處理,但是執行出了問題,程式終止,後續程式碼不會執行
(推薦執行前檢查程式碼邏輯,其次可以像處理編譯時期異常一樣try..catch

throw: 在方法內部丟擲,後面跟上具體的異常物件

(面試題:throwthrows的區別)}
throws:
用在方法的聲明後面,後面跟的是異常的類名
異常的類名可以是多個,多個類名之間使用逗號隔開
表示將異常丟擲,交給呼叫者去處理
throws表示的是一種可能性,並不一定會發生這些異常

throw:
用在方法的內部,後面跟的是異常的物件;
只能是一個物件,不能丟擲多個
表示丟擲異常,由方法內部的語句體去做處理
throw表示的是方法內部一定會出現某種異常,是確定的。

 

public class ExceptionDemo5 {
    public static void main(String[] args) {
        try {
            function();
        } catch (ParseException e) {
            e.printStackTrace();
        }catch (ArithmeticException ae){
            ae.printStackTrace();
        }

//        function();

//        function2();

//        try {
//            function3();
//        }catch (ArithmeticException ae){
//            ae.printStackTrace();
//        }


        System.out.println("你好!!!");
    }

    public static void function3() {
        int a = 10;
//        int b = 2;
        int b = 0;
        if (b != 0) {
            System.out.println(a/b);
        }else {
            System.out.println("除數為0");
            //在方法內部丟擲,丟擲的是一個具體的物件,表示一定會出現這樣的問題
            throw new ArithmeticException();
        }
    }


    public static void function2() throws ArithmeticException {
        int a = 10;
//        int b = 2;
        int b = 0;
//        if(b!=0){
//            System.out.println(a/b);
//        }else {
//            System.out.println("除數為0");
//        }
//        try {
//            System.out.println(a/b);
//        }catch (ArithmeticException ae){
//            ae.printStackTrace();
//        }

        System.out.println(a / b);
    }

    public static void function() throws ParseException,ArithmeticException {
        String s = "2020-04-06 16:08:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);

        int a = 10;
        int b = 0;
        System.out.println(a / b);
    }

}

 

 處理異常的格式:
1try...catch...
2try...catch...catch
3try...catch...catch...finally
4try...catch..finally

注意:
1、無論try裡面的程式碼會不會報錯,都會執行finally中的語句
特殊情況:在執行finally之前,程式就已經退出

 

public class ExceptionDemo6 {
    public static void main(String[] args) {
        String s = "2020-04-06 16:45:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = sdf.parse(s);
            System.exit(0); //這個語句就是結束程式執行
        } catch (ParseException e) {
            e.printStackTrace();
        } finally {
            //通常情況下,這裡面放的是釋放資源的程式碼
            System.out.println("這是finally中的語句");
        }

        System.out.println("你好!!");


    }
}

 

如果方法中有try..catch..finally,並且,在catch中有return語句,結果會是什麼樣子呢?
finally之前執行還是在finally之後執行呢?在finally執行中間

面試題:finally,final,finalize他們三個你認識嗎,他們什麼什麼區別?
回答:都認識,但是他們三個之間沒有任何關係,只是長得像罷了。finally是在異常處理中遇到,一般是用於釋放資源的
finaljava中的一個關鍵字,他可以修飾類,成員變數,成員方法,修飾類,類不能被繼承,修飾成員變數,
變數變常量,修飾成員方法,方法不能被重寫;finalizeObject類中的一個方法名,該方法是用於垃圾回收的
但是什麼時候回收不確定。
public class ExceptionDemo7 {
    public static void main(String[] args) {
        System.out.println(fun()); // a =
    }
    public static int fun(){
        int a = 20;
        int b = 0;
        try {
            a = 30;
            System.out.println(a/b);
            a = 40; // 這一行肯定不會執行
        }catch (ArithmeticException ae){
            a = 60;
//            ae.printStackTrace();
            return a;
            //當程式走到這裡的時候,方法其實已經有了一個返回值路徑,返回的就是60。
            //但是程式此刻還沒有結束,所以依舊會走finally中的語句

        }finally {
            a = 50;
            System.out.println(a);
//            return a;
        }
        return a; // 這裡其實是為了語法的正確,加了return
    }
}
異常在繼承關係中的使用:
1、子類重寫父類方法時,子類的方法必須丟擲相同的異常或父類異常的子類。(父親壞了,兒子不能比父親更壞)
2、如果父類丟擲了多個異常,子類重寫父類時,只能丟擲相同的異常或者是他的子集,子類不能丟擲父類沒有的異常
3、如果被重寫的方法沒有異常丟擲,那麼子類的方法絕對不可以丟擲異常,如果子類方法內有異常發生,
那麼子類只能try,不能throws