7-Java異常

異常:
現(xiàn)實生活的病
現(xiàn)實生活中萬物在發(fā)展和變化會出現(xiàn)各種各樣不正常的現(xiàn)象。
1:例如:人的成長過程中會生病。
|——病
|——不可治愈(癌癥晚期)
|——可治愈
|——小病自行解決(上火,牙痛)
|——去醫(yī)院(感冒,發(fā)燒)
現(xiàn)實生活中的很多病況從面向?qū)ο蟮慕嵌瓤紤]也是一類事物,可以定義為類。

java中可以通過類對這一類不正常的現(xiàn)象進行描述,并封裝為對象。
java的異常體系包含在java.lang這個包默認(rèn)不需要導(dǎo)入。

java異常體系
|——Throwable (實現(xiàn)類描述java的錯誤和異常)
|——Error (錯誤)一般不通過代碼去處理。
|——Exceprion (異常)
|——RuntimeException (運行時異常)
|——非運行時異常

常見的Error;

/*
  java虛擬機默認(rèn)管理了64M的內(nèi)存,一數(shù)組需要1G的內(nèi)存,這樣子就會造成內(nèi)存溢出
byte[] but = new byte[1024*1024*1024]  //1K-->1M-->1G
System.out.println(buf);
*/
內(nèi)存溢出,需要的內(nèi)存超出了Java虛擬機管理的內(nèi)存范圍
找不到類文件

它指的是一個合理的應(yīng)用程序不能截獲的嚴(yán)重的問題。大多數(shù)都是反常的情況。錯誤是JVM的一個故障(雖然它可以是任何系統(tǒng)級的服務(wù))。所以,錯誤是很難處理的,一般的開發(fā)人員(當(dāng)然不是你)是無法處理這些錯誤的。比如內(nèi)存溢出.

異常體系圖的對應(yīng)

class ExceptionDemo1{
    public static div(int a, int b){
       int c = a/b;
        System.out.printlin("----" + c);
    }
    public static void main(String args[]){
         ExceptionDemo1 demo1 = ExceptionDemo1();
          demo1.div(4,0);
    }
}
異常

異常

Throwable類
*toString() 輸出該異常的類名。
getMessage() 輸出異常的信息,需要通過構(gòu)造方法傳入異常信息(例如病態(tài)信息)。
printStackTrace() 打印棧信息。

人生?。毫鞅翘?,感冒,呼吸道感染,肺炎。。。最后體現(xiàn)的是肺炎。
醫(yī)生要處理需要獲知這些信息。從外到里處理。最后找病源

class Demo6 {

 public static void main(String[] args) {

   // Throwable able=newThrowable();
   Throwable able = new Throwable("想吐。。。");
   System.out.println(able.toString()); // 輸出該異常的類名
   System.out.println(able.getMessage()); // 輸出異常的信息
   able.printStackTrace(); // 打印棧信息
   }
}

程序中的異常處理
當(dāng)除數(shù)是非0,除法運算完畢,程序繼續(xù)執(zhí)行。
當(dāng)除數(shù)是0,程序發(fā)生異常,并且除法運算之后的代碼停止運行。因為程序發(fā)生異常需要進行處理。

class Demo7 {

   public static void main(String[] args) {
   div(2, 0);
   System.out.println("over");
 }

 public static void div(int x, int y) {
        //該行代碼的y值可能是0,程序會出現(xiàn)異常并停止
 System.out.println(x / y);
 System.out.println("除法運算");
 }
}
//ArithmeticException 

疑問: 出現(xiàn)異常如何處理?
自行處理
try{//可能發(fā)生異常的代碼 }catch(異常類 變量名){//處理}。
案例除法運算的異常處理。
如果沒有進行try catch處理,出現(xiàn)異常程序就停止。進行處理后,程序會繼續(xù)執(zhí)行。

多個異常
案例print方法,形參中增加數(shù)組。
在print方法中操作數(shù)組會發(fā)生新的異常
ArrayIndexOutOfBoundsException,NullPointerException),如何處理?
使用將可能發(fā)生異常的代碼放入try語句中,添加多個catch語句即可。
可以處理多種異常,但是同時只能處理一種異常。
try中除0異常和數(shù)組角標(biāo)越界同時出現(xiàn),只會處理一種。

public class Demo8 {

   public static void main(String[] args) {

 System.out.println();
 int[] arr = { 1, 2 };
 arr = null;

 // print (1, 0, arr);
 print (1, 2, arr);

 System.out.println("over");
 } 

   public static void print(int x,int y, int[] arr) {

   try{
     System.out.println(arr[1]);
     System.out.println(x / y);
 } catch (ArithmeticException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
 System.out.println("算術(shù)異常。。。");
 } catch (ArrayIndexOutOfBoundsException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
   System.out.println("數(shù)組角標(biāo)越界。。。");
 } catch (NullPointerException e) {
   e.toString();
   e.getMessage();
   e.printStackTrace();
   System.out.println("空指針異常。。。");
 }
   System.out.println("函數(shù)執(zhí)行完畢");
 }
}

總結(jié)

**程序中有多個語句可能發(fā)生異常,可以都放在try語句中。并匹配對個catch語句處理。
如果異常被catch匹配上,接著執(zhí)行try{}catch(){} 后的語句。沒有匹配上程序停止。
try中多個異常同時出現(xiàn),只會處理第一條出現(xiàn)異常的一句,剩余的異常不再處理。
使用多態(tài)機制處理異常。
程序中多態(tài)語句出現(xiàn)不同異常,出現(xiàn)了多個catch語句。簡化處理(相當(dāng)于急診)。
使用多態(tài),使用這些異常的父類進行接收。(父類引用接收子類對象)
**

public static void div(int x, int y, int[] arr, Father f) {
    try {

        System.out.println(arr[1]); // 數(shù)組越界
        System.out.println(x / y); // 除零
        Son s = (Son) f; // 類型轉(zhuǎn)換

      } catch (Exception e) {
            
            e.toString();
            e.getMessage();
            e.printStackTrace();
            System.out.println("出錯啦");

        }

        System.out.println("函數(shù)執(zhí)行完畢");

    }

多個catch語句之間的執(zhí)行順序。
是進行順序執(zhí)行,從上到下。
如果多個catch 內(nèi)的異常有子父類關(guān)系。
子類異常在上,父類在最下。編譯通過運行沒有問題
父類異常在上,子類在下,編譯不通過。(因為父類可以將子類的異常處理,子類的catch處理不到)。
多個異常要按照子類和父類順序進行catch

class Father {

}

class Son extends Father {

}
public class Demo8 {
    public static void main(String[] args) {



        System.out.println();

        int[] arr = { 1, 2 };

        arr = null;

        Father f = new Father();

        div(1, 0, arr, f);

        

        System.out.println("over");

    }



    public static void div(int x, int y, int[] arr, Father f) {



        try {

            System.out.println(arr[1]);

            System.out.println(x / y);

            Son s = (Son) f;



        } catch (ArithmeticException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("算術(shù)異常。。。");

        } catch (ArrayIndexOutOfBoundsException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("數(shù)組角標(biāo)越界。。。");

        } catch (NullPointerException e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("空指針異常。。。");

        } catch (Exception e) {

            e.toString();

            e.getMessage();

            e.printStackTrace();

            System.out.println("出錯啦");

        }

        System.out.println("函數(shù)執(zhí)行完畢");

    }

}

總結(jié)

*處理異常應(yīng)該catch異常具體的子類,可以處理的更具體,不要為了簡化代碼使用異常的父類。
疑惑:感覺異常沒有作用.

拋出處理

定義一個功能,進行除法運算例如(div(int x,int y))如果除數(shù)為0,進行處理。
功能內(nèi)部不想處理,或者處理不了。就拋出使用throw new Exception("除數(shù)不能為0"); 進行拋出。拋出后需要在函數(shù)上進行聲明,告知調(diào)用函數(shù)者,我有異常,你需要處理如果函數(shù)上不進行throws 聲明,編譯會報錯。例如:未報告的異常 java.lang.Exception;必須對其進行捕捉或聲明以便拋出throw new Exception("除數(shù)不能為0");

public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調(diào)用者。



        if (y == 0) {

    throw new Exception("除數(shù)為0"); // throw關(guān)鍵字后面接受的是具體的異常的對象

        }

        System.out.println(x / y);

        System.out.println("除法運算");

    }

main方法中調(diào)用除法功能
調(diào)用到了一個可能會出現(xiàn)異常的函數(shù),需要進行處理。

1:如果調(diào)用者沒有處理會編譯失敗。
如何處理聲明了異常的函數(shù)。

  • try{}catch(){}
public static void main(String[] args) {



        try {

            div(2, 0);

        } catch (Exception e) {

            e.printStackTrace();

        }

        System.out.println("over");



    }



    public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調(diào)用者。



        if (y == 0) {

    throw new Exception("除數(shù)為0"); // throw關(guān)鍵字后面接受的是具體的異常的對象

        }

        System.out.println(x / y);

        System.out.println("除法運算");

    }

}

2:繼續(xù)拋出throws

class Demo9 {



   public static void main(String[] args) throws Exception {

       div(2, 0);

       System.out.println("over");

   }



   public static void div(int x, int y) throws Exception { // 聲明異常,通知方法調(diào)用者。

   if (y == 0) {

       throw new Exception("除數(shù)為0"); // throw關(guān)鍵字后面接受的是具體的異常的對象

   }



       System.out.println(x / y);

       System.out.println("除法運算");

   }

}

throw和throws的區(qū)別

相同:都是用于做異常的拋出處理的。
不同點:

//throws 處理

public static void main(String[] args) throws InterruptedException {

        Object obj = new Object();

        obj.wait();



    }

public static void main(String[] args) {



        //try catch 處理

        Object obj = new Object();

        try {

            obj.wait();

        } catch (InterruptedException e) {

            

            e.printStackTrace();

        }



    }

**使用的位置: throws 使用在函數(shù)上,throw使用在函數(shù)內(nèi)
后面接受的內(nèi)容的個數(shù)不同:
throws 后跟的是異常類,可以跟多個,用逗號隔開。
throw 后跟異常對象。
**

總結(jié)

  • try語句不能單獨存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結(jié)構(gòu)。
  • catch語句可以有一個或多個,finally語句最多一個,try、catch、finally這三個關(guān)鍵字均不能單獨使用。
  • try、catch、finally三個代碼塊中變量的作用域分別獨立而不能相互訪問。如果要在三個塊中都可以訪問,則需要將變量定義到這些塊的外面。
  • 多個catch塊時候,Java虛擬機會匹配其中一個異常類或其子類,就執(zhí)行這個catch塊,而不會再執(zhí)行別的catch塊。(子類在上,父類在下)。
  • throw語句后不允許有緊跟其他語句,因為這些沒有機會執(zhí)行。
  • 如果一個方法調(diào)用了另外一個聲明拋出異常的方法,那么這個方法要么處理異常,要么聲明拋出。

自定義異常

問題:現(xiàn)實中會出現(xiàn)新的病,就需要新的描述。
分析: java的面向?qū)ο笏枷雽⒊绦蛑谐霈F(xiàn)的特有問題進行封裝。
案例: 定義功能模擬凌波登錄。(例如:lb(String ip))需要接收ip地址
當(dāng)沒有ip地址時,需要進行異常處理。

  1. 當(dāng)ip地址為null是需要throw new Exception("無法獲取ip");
    • 但Exception是個上層父類,這里應(yīng)該拋出更具體的子類。
/*

 自定義異常  

 */

class NoIpException extends Exception {



    NoIpException() {



    }



    NoIpException(String message) {

        super(message);

    }



}



class Demo10 {



    public static void main(String[] args) throws NoIpException {



        System.out.println();

        String ip = "192.168.10.252";

        ip = null;

        try {

            Lb(ip);

        } catch (NoIpException e) {

            System.out.println("程序結(jié)束");

        }



    }






    public static void Lb(String ip) throws NoIpException {

        if (ip == null) {

            // throw new Exception("沒插網(wǎng)線吧,小白");

            throw new NoIpException("沒插網(wǎng)線吧,小白");

        }



        System.out.println("醒醒了,Jarret.Yang開始上課了。");

    }
  • 可以自定義異常
    自定義描述沒有IP地址的異常(NoIpException)。
  1. 和sun的異常體系產(chǎn)生關(guān)系。繼承Exception類,自定義異常類名也要規(guī)范,結(jié)尾加上Exception,便于閱讀

*案例:模擬吃飯沒帶錢的問題
定義吃飯功能,需要錢。(例如:eat(double money))
如果錢不夠是不能吃放,有異常。
自定義NoMoneyException();繼承Exception 提供有參無參構(gòu)造,調(diào)用父類有參構(gòu)造初始化。at 方法進行判斷,小于10塊,throw NoMoneyException("錢不夠");
eat 方法進行聲明,throws NoMoneyException
如果錢不夠老板要處理。調(diào)用者進行處理。try{}catch(){} 。

class NoMoneyException extends Exception {



    NoMoneyException() {



    }



    NoMoneyException(String message) {

        super(message);

    }

}



class Demo11 {



    public static void main(String[] args) {



        System.out.println();

        try {

            eat(0);

        } catch (NoMoneyException e) {

            System.out.println("跟我干活吧。");

        }

    }



    

    public static void eat(double money) throws NoMoneyException {

        if (money < 10) {

            throw new NoMoneyException("錢不夠");

        }

        System.out.println("吃桂林米粉");

    }

}

運行時異常和非運行時異常

RuntimeException

RunntimeException的子類:

  • ClassCastException
    多態(tài)中,可以使用Instanceof 判斷,進行規(guī)避

  • ArithmeticException
    進行if判斷,如果除數(shù)為0,進行return

  • NullPointerException
    進行if判斷,是否為null

  • ArrayIndexOutOfBoundsException
    使用數(shù)組length屬性,避免越界

  • 這些異常時可以通過程序員的良好編程習(xí)慣進行避免的
    1:遇到運行時異常無需進行處理,直接找到出現(xiàn)問題的代碼,進行規(guī)避。
    2:就像人上火一樣牙疼一樣,找到原因,自行解決即可
    3:該種異常編譯器不會檢查程序員是否處理該異常
    4:如果是運行時異常,那么沒有必要在函數(shù)上進行聲明。

案例
1:除法運算功能(div(int x,int y))
2:if判斷如果除數(shù)為0,throw new ArithmeticException();
3:函數(shù)聲明throws ArithmeticException
4:main方法調(diào)用div,不進行處理
5:編譯通過,運行正常
6:如果除數(shù)為0,報異常,程序停止。
7:如果是運行時異常,那么沒有必要在函數(shù)上進行聲明。

Object類中的wait()方法,內(nèi)部throw了2個異常 IllegalMonitorStateException InterruptedException

1:只聲明了一個(throws) IllegalMonitorStateException是運行是異常沒有聲明。

class Demo12 {



    public static void main(String[] args){

        div(2, 1);

    }



    public static void div(int x, int y) {

        if (y == 0) {

            throw new ArithmeticException();  

        }

        System.out.println(x / y);

    }

}
非運行時異常(受檢異常)

如果出現(xiàn)了非運行時異常必須進行處理throw或者try{}catch(){}處理,否則編譯器報錯。
1;IOException 使用要導(dǎo)入包import java.io.IOException;
2:ClassNotFoundException
2;例如人食物中毒,必須進行處理,要去醫(yī)院進行處理。

案例
1:定義一測試方法拋出并聲明ClassNotFoundException(test())
2:main方法調(diào)用test
3:編譯報錯

  • 未報告的異常 java.lang.ClassNotFoundException;必須對其進行捕捉或聲明以便拋出
public void isFile(String path){

        try

        {

            /*

            根據(jù)文件的路徑生成一個文件對象,如果根據(jù)該路徑找不到相應(yīng)的文件,

            則沒法生成文件對象。

            */

            File file = new File(path);

            //讀取文件的輸入流

            FileInputStream input = new FileInputStream(file);

            //讀取文件

            input.read();

        }

        catch (NullPointerException e)

        {

            System.out.println("讀取默認(rèn)的文件路徑..");

        }

        

    }

4:Sun 的API文檔中的函數(shù)上聲明異常,那么該異常是非運行是異常,
調(diào)用者必須處理。
5:自定義異常一般情況下聲明為非運行時異常

  • 函數(shù)的重寫和異常
    • 運行時異常
      1:案例定義Father類,定義功能拋出運行是異常,例如(test() throw
      ClassCastException)
      2:定義Son類,繼承Father類,定義test方法,沒有聲明異常
      3:使用多態(tài)創(chuàng)建子類對象,調(diào)用test方法
      4:執(zhí)行子類方法
      • 函數(shù)發(fā)生了重寫,因為是運行時異常,在父類的test方法中,可以聲明throws 也可以不聲明throws
class Father {

    void test() throws ClassCastException { // 運行時異常

        System.out.println("父類");

        throw new ClassCastException();

    }

}



class Son extends Father {

    void test() {

        System.out.println("子類");

    }

}

class Demo14 {



    public static void main(String[] args) {

        Father f = new Son();

        f.test();

    }

}

2:非運行時異常
1:定義父類的test2方法,拋出非運行時異常,例如拋出ClassNotFoundException

  • 1:此時父類test2方法必須聲明異常,因為是非運行時異常
  • 2:Son類定義test2 方法,拋出和父類一樣的異常,聲明異常
  • 3:使用多態(tài)創(chuàng)建子類對象,調(diào)用test方法,調(diào)用test2方法,

1:聲明非運行時異常的方法,在調(diào)用時需要處理,所以在main方法調(diào)用時throws
2:實現(xiàn)了重寫,執(zhí)行子類的test2方法
3:總結(jié)子類重寫父類方法可以拋出和父類一樣的異常,或
者不拋出異常。

//  1 子類覆蓋父類方法父類方法拋出異常,子類的覆蓋方法可以不拋出異常

class Father {

    void test() throws ClassNotFoundException { // 非運行時異常

        System.out.println("父類");

        throw new ClassNotFoundException();

    }

}



class Son extends Father {

    void test() {

        System.out.println("子類");

        // 父類方法有異常,子類沒有。

    }

}

class Demo14 {



    public static void main(String[] args) throws ClassNotFoundException  {

        Father f = new Son();

        f.test();



    }

}

4:子類拋出并聲明比父類大的異常例如子類test2方法拋出Exception
1:編譯失敗,無法覆蓋
2:子類不能拋出父類異常的父類。
3:總結(jié)子類不能拋出比父類的異常更大的異常。

//2:子類覆蓋父類方法不能比父類拋出更大異常

class Father {

    void test() throws Exception {

        // 非運行時異常

        System.out.println("父類");

        throw new Exception();

    }

}



class Son extends Father {

    void test() throws ClassNotFoundException { // 非運行時異常

        System.out.println("子類");

        throw new ClassNotFoundException();

    }

}

class Demo14 {



    public static void main(String[] args) throws Exception {

        Father f = new Son();

        f.test();



    }

}

3:總結(jié)
1:子類覆蓋父類方法是,父類方法拋出異常,子類的覆蓋方法可以不拋
出異常,或者拋出父類方法的異常,或者該父類方法異常的子類。
2:父類方法拋出了多個異常,子類覆蓋方法時,只能拋出父類異常的子

3:父類沒有拋出異常子類不可拋出異常

  • 子類發(fā)生非運行時異常,需要進行try{}catch的(){}處理,不能
    拋出。

4:子類不能比父類拋出更多的異常

finally

  • 實現(xiàn)方式一:
    try{ // 可能發(fā)生異常的代碼 } catch( 異常類的類型 e ){ // 當(dāng)發(fā)生指定異常的時候的處理代碼 }catch...
    比較適合用于專門的處理異常的代碼,不適合釋放資源的代碼。
  • 實現(xiàn)方式二:
    try{ } catch(){} finally{ // 釋放資源的代碼 }
    finally塊是程序在正常情況下或異常情況下都會運行的。
    比較適合用于既要處理異常又有資源釋放的代碼
  • 實現(xiàn)方式三
    try{ }finally{ // 釋放資源 }
    比較適合處理的都是運行時異常且有資源釋放的代碼。
    • finally:關(guān)鍵字主要用于釋放系統(tǒng)資源。
    • 在處理異常的時候該語句塊只能有一個。
    • 無論程序正常還是異常,都執(zhí)行finally。
    • finally是否永遠(yuǎn)都執(zhí)行?
      1:只有一種情況,但是如果JVM退出了System.exit(0),finally就不執(zhí)行。
      2:return都不能停止finally的執(zhí)行過程。

案例使用流

  • 使用FileInputStream加載文件。
    導(dǎo)包import java.io.FileInputStream;
  • FileNotFoundException
    導(dǎo)入包import java.io.FileNotFoundException;
  • IOException
    import java.io.IOException;
public class FinallyDemo {

    // 本例子使用finally 關(guān)閉系統(tǒng)資源。

    public static void main(String[] args) {



        FileInputStream fin = null;

        try {

            System.out.println("1創(chuàng)建io流可能出現(xiàn)異常");

            fin = new FileInputStream("aabc.txt"); // 加載硬盤的文本文件到內(nèi)存,通過流

            // System.out.println(fin);

        } catch (FileNotFoundException e) {

            System.out.println("2沒有找到abc.txt 文件");

            System.out.println("3catch 了");

            // System.exit(0);

            // return;

        }

        // finally

        finally {

            System.out.println("4fianlly執(zhí)行");

            if (fin != null) { // 如果流對象為null 流對象就不存在,沒有必要關(guān)閉資源

                try {

                    fin.close();

                } catch (IOException e) {

                    e.printStackTrace();

                    System.out.println("close 異常");

                }



            }

            System.out.println("5finally over");

        }

        System.out.println("6mainover");

    }

}
// 2:無論程序正常還是異常,都執(zhí)行finally。 但是遇到System.exit(0); jvm退出。

// finally用于必須執(zhí)行的代碼, try{} catch(){}finally{}

// try{}finally{}

思考:

為什么要將一個類定義成內(nèi)部類?
匿名內(nèi)部類的使用和細(xì)節(jié)(面試題)
異常的思想和體系特點?
throws和throw的如何使用?
什么時候try 什么時候throws?
編譯時被檢測異常和運行時異常的區(qū)別?
異常的所有細(xì)節(jié)?
finally的應(yīng)用?
包的作用,名稱空間的定義和理解?
jar包的基本使用。只要將類和包都存儲到j(luò)ar中,方便于使用。只要將jar配置到classpath路徑下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容