Java基礎---異常,包

異常

1.定義

異常指的是在程序運行過程中發生的異常事件,通常是由硬件問題或者程序設計問題所導致的。在Java等面向對象的編程語言中異常屬於對象。

Java異常類層次結構圖:
這裏寫圖片描述

2.異常由來:

編程中對於那些會出現的問題,Java採用異常機制來解決。
最常使用的就是try{}catch{}

本質:java對不正常情況進行描述後的對象體現。
程序可能出現的錯誤或問題:
    a、用戶輸入錯誤導致的異常:如用戶不正常使用程序,輸入一些非法參數
    b、設備硬件等發生的錯誤:如硬盤損壞等
    c、物理限制:如存儲空間不足等
    d、代碼錯誤:在程序編寫的方法可能不正確,數組越界,返回錯誤參數等。

3.異常體系

Throwable 類

是 Java 語言中所有錯誤或異常的超類。只有當對象是此類(或其子類之一)的實例時,才能通過 Java 虛擬機或者 Java throw 語句拋出。類似地,只有此類或其子類之一纔可以是 catch 子句中的參數類型。 

有兩個重要的子類:Exception(異常)和 Error(錯誤)

Error(錯誤)

是程序無法處理的錯誤,表示運行程序中較嚴重的問題。
這些錯誤表示故障發生於虛擬機自身、或者發生在虛擬機試圖執行應用時,如Java虛擬機運行錯誤(Virtual MachineError)、類定義錯誤(NoClassDefFoundError)等。這些錯誤是不可查的,因爲它們在應用程序的控制和處理能力之 外,而且絕大多數是程序運行時不允許出現的狀況。對於設計合理的應用程序來說,即使確實發生了錯誤,本質上也不應該試圖去處理它所引起的異常狀況。在 Java中,錯誤通過Error的子類描述。

Exception(異常)

是程序本身可以處理的異常。
RuntimeException類是他的一個比較特殊的類。

RuntimeException 類:
    RuntimeException 類及其子類表示“JVM 常用操作”引發的錯誤。例如,若試圖使用空值對象引用、除數爲零或數組越界,則分別引發運行時異常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。 

注意:異常和錯誤的區別:異常能被程序本身處理,錯誤是無法處理。

4.異常分類

1.Java的異常

Java的異常(包括Exception和Error)分爲可查的異常(checked exceptions)和可不查的異常(unchecked exceptions)。

可查異常(編譯器要求必須處置的異常):

 程序在運行時,在一定程度上可以預知的異常,並可以採取某種方式進行處理。
 除了RuntimeException及其子類以外,其他的Exception類及其子類都屬於可查異常。這種異常的特點是Java編譯器會檢查它,也就是說,當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,否則編譯不會通過。

可不查異常(編譯器不要求強制處置的異常):

包括運行時異常(RuntimeException與其子類)和錯誤(Error)。
這類異常編譯時,編譯器不會去檢查。

2.Exception異常

Exception 這種異常分兩大類運行時異常和非運行時異常(編譯異常)。程序中應當儘可能去處理這些異常。

運行時異常:

RuntimeException及其子類,如NullPointerException(空指針異常)、IndexOutOfBoundsException(下標越界異常)等。這些異常編譯器不檢查,即使不使用try-catch捕獲,或使用throws拋出,編譯器也不會報錯,但會在運行時觸發。
這些異常一般出在邏輯上,在程序設計時應該從邏輯角度儘可能避免這類異常。

非運行時異常 (編譯異常):

除RuntimeException及其子類外的異常,類型上屬於Exception類及其子類。
編譯器會檢查此類一場,如果不處理,程序是無法編譯通過的。

總結:根據編譯器是否檢查來進行劃分。
總的來說,RuntimeException及其子類外的異常編譯器不進行檢查,其他Exception都需要處理。

異常處理

對於運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不同:

 a.運行時異常:java允許可以不拋出,不捕獲;運行時由系統由系統拋出。
 b.Error,不拋出,不捕獲,因爲Error是java所不允許發生的。
 c.可查行異常,必須捕獲或者拋出。

一個方法所能捕捉的異常,一定是Java代碼在某處所拋出的異常。簡單地說,異常總是先被拋出,後被捕捉的。

異常處理有兩種方式:捕捉異常(try-catch),拋出異常(throws)

1.捕捉異常

java提供了特有的語句進行處理:
try

    {

             需要被檢測的代碼。

    }

    catch(異常類  變量)

    {

             處理異常的代碼;(處理方式)

    }

    finally

    {

             一定會執行的語句;

    }

注意:

    1)finally中定義的通常是關閉資源代碼。因爲資源必須釋放。

    2)如果在一個功能中,定義了一些必須要執行的代碼,可以用try{}finally{}的方式,將一定執行的代碼放在finally代碼塊中。

    3)finally只有一種情況不會執行。當執行到System.exit(0);fianlly不會執行。
    public static void main(String[] args) {
        int a = 6;
        int b = 0;
        try {
            System.out.println("a/b的值是:"+ a / b);
        } catch (ArithmeticException e) {
            System.out.println("程序出現異常,變量b不能爲0。");
        }
        System.out.println("程序正常結束。");
    }
}

分析:此例中由try中監控區,檢測到“除數爲0”從而引發ArithmeticException異常,由異常處理器catch捕獲,並處理。
但是,實際上,”除數爲0“ArithmeticException異常是RuntimeException子類,會由系統自動拋出,不需要使用throw語句。

需要注意的是,一旦某個catch捕獲到匹配的異常類型,將進入異常處理代碼。一經處理結束,就意味着整個try-catch語句結束。其他的catch子句不再有匹配和捕獲異常類型的機會。
對於有多個catch子句的異常程序而言,應該儘量將捕獲底層異常類的catch子 句放在前面,同時儘量將捕獲相對高層的異常類的catch子句放在後面。否則,捕獲底層異常類的catch子句將可能會被屏蔽。
這裏寫圖片描述

小結:

try 塊:用於捕獲異常。其後可接零個或多個catch塊,如果沒有catch塊,則必須跟一個finally塊。
catch 塊:用於處理try捕獲到的異常。

finally塊:無論是否捕獲或處理異常,finally塊裏的語句都會被執行。當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。在以下4種特殊情況下,finally塊不會被執行:
1)在finally語句塊中發生了異常。
2)在前面的代碼中用了System.exit()退出程序。
3)程序所在的線程死亡。
4)關閉CPU。

2.拋出異常

可以通過throws和throw拋出異常。
1)throws
定義:

 如果一個方法可能會出現異常,但沒有能力處理這種異常,可以在方法聲明處用throws子句來聲明拋出異常。例如汽車在運行時可能會出現故障,汽車本身沒辦法處理這個故障,那就讓開車的人來處理。

throws語句用在方法定義時聲明該方法要拋出的異常類型,如果拋出的是Exception異常類型,則該方法被聲明爲拋出所有的異常。多個異常可使用逗號分割。throws語句的語法格式爲:

methodname throws Exception1,Exception2,..,ExceptionN  
{  
}  

方法名後的throws Exception1,Exception2,…,ExceptionN 爲聲明要拋出的異常列表。當方法拋出異常列表的異常時,方法將不對這些類型及其子類類型的異常作處理,而拋向調用該方法的方法,由他去處理。例如:

import java.io.*;

public class Test1 {

    public static void method() throws IOException {
        File f = new File("r:\\");
    }

    public static void main(String[] args) {
        //此處報錯,Unhandled exception type IOException未處理異常
        method();
    }

}

原因:IOException是Exception子類,是編譯異常,必須捕獲,method()方法使用throws向上層調用(main函數)拋出了,但是main函數未處理,所以造成了錯誤。
解決:使用try-catch捕獲並處理。
Throws拋異常的原則:

    1)不可查異常(unchecked exception)RuntimeException和Error異常可以不拋出,但是可查異常(checked exception)必須被拋出或者被捕獲,否則編譯會報錯。

    2)僅當拋出了異常,該方法的調用者才必須處理或者重新拋出該異常。當方法的調用者無力處理該異常的時候,應該繼續拋出,而不是囫圇吞棗。
public class Test1 {

    void method() throws IOException {
        File f = new File("r:\\");
    }

    // 編譯錯誤,必須捕獲或者聲明IOException
    void method1() {
        method();
    }

    // 合法,聲明拋出了IOException
    void method2() throws IOException {
        method();
    }

    // 合法,聲明拋出Exception,IOException是Exception的子類
    void method3() throws Exception {
        method();
    }

    // 合法,捕獲了IOException
    void method4() {
        try {
            method();
        } catch (IOException e) {
        }
    }

    // 不合法,又拋出了一個IOException,必須拋出或者再次捕獲
    void method5() {
        try {
            method();
        } catch (IOException e) {
            throw new IOException();
        }
    }

    // 合法,再次拋出的新的異常
    void method6() throws Exception {
        try {
            method();
        } catch (IOException e) {
            throw new Exception();
        }
    }
}
        3)在子父類覆蓋時:
          a,子類拋出的異常必須是父類的異常的子類或者子集。
          b,如果父類或者接口沒有異常拋出時,子類覆蓋出現異常,只能try不能拋。
class T1 {
    void method() throws IOException {
    }
}
class T2 extends T1{
//錯誤,子類拋出的異常不是父類拋出異常的子類
    void method()throws Exception {
    }
}

2)throw拋出異常
在函數體內使用,即拋出一個一場對象。形如:

throw new Throwable();

該對象是人爲拋出的,雖然和程序運行產生的不同,但是仍是需要拋出或者捕獲的。

Throwable

Throwable中的方法:

1.getMessage():獲取異常信息,返回字符串。
2.toString():獲取異常類名和異常信息,返回字符串。
3.printStackTrace():獲取異常類名和異常信息,以及異常出現在程序中的位置,返回值void。
4.printStackTrace(PrintStreams):通常用該方法將異常內容保存在日誌文件中,以便查閱。

自定義異常:

/***
 * 自定義異常
 */
class Demo{
    //除法,拋出我的自定義異常
    int div(int a, int b) throws MyException{
        if(b==0){
            throw new MyException("除數不能爲負數!");
        }
        return a/b;
    }
}
public class Test3 {

    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        try {
            Demo d = new Demo();
            int s = d.div(a, b);
        } catch (MyException e) {
            // TODO: handle exception
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }
}

class MyException extends Exception {
    /***
     * 自定義異常的構造方法,信息的傳遞通過有參構造方法,
     *  父類通過有參構造方法傳遞的參數來打印消息
     */
    public MyException(String MyMessage) {
        super(MyMessage);
    }
}

小測試:

import java.util.*;

/***
 *  老師使用電腦講課。
 * 
 *         描述電腦: 1、電腦運行 2、電腦重啓 描述電腦問題: 1、電腦藍屏了 2、電腦起火了
 * 
 *         描述老師: 1、老師使用電腦 2、老師講課。
 * 
 *         描述老師可能出現的問題: 
 *         1、老師不能繼續講課了。
 *         2.電腦藍屏,重新啓動 
 *                  a.多次重啓後,成功 
 *                  b.多次藍屏重啓後,電腦着火了
 *         3.一次啓動成功,老師開始講課
 */
//藍屏異常
class BlueScreenException extends Exception {
    public BlueScreenException(String message) {
        super(message);
    }
}

//電腦着火
class FireBreakException extends Exception {
    public FireBreakException(String message) {
        super(message);
    }
}
//電腦類
class Computer {
    // 隨機產生一個數,來模擬電腦啓動
    int i;
    //啓動
    void run() throws BlueScreenException, FireBreakException {
        i = (int) (Math.random()*3+1);
        if(1==i)
        {
            System.out.println("電腦正常啓動");
        } else if(2==i)
        {
            throw new BlueScreenException("電腦藍屏了!");//藍屏異常
        } else
        {
            throw new FireBreakException("電腦着火了!");//着火異常
        }
    }
    //重啓
    void reset() {
        System.out.println("電腦重新啓動");
        try {
            run();
        } catch (BlueScreenException e) {
            System.out.println(e.getMessage());
            reset();
        } catch (FireBreakException e) {

            System.out.println("多次重啓,着火了!");
        }
    }
}

//無法上課的異常
class BreakTeachingException extends Exception{
    public BreakTeachingException(String message){
        super(message);
    }
}


//老師類
class Teacher{
    private Computer c = new Computer();
    void teach() throws BreakTeachingException{
        try {
            c.run();
            System.out.println("老師開始上課!");
        } catch (BlueScreenException e) {

            System.out.println(e.getMessage());
            c.reset();
        } catch (FireBreakException e) {

            throw new BreakTeachingException("老師無法上課,原因"+e.getMessage());
        }
    }
}
public class Test4 {
    public static void main(String[] args) {
        Teacher t = new Teacher();
        try {
            t.teach();
        } catch (BreakTeachingException e) {

            e.printStackTrace();
            System.out.println("暫停上課,電腦着火了!");
        }
    }
}

一次啓動成功,老師開始講課:
這裏寫圖片描述
一次啓動,電腦着火:
這裏寫圖片描述
多次藍屏重啓後成功
這裏寫圖片描述
多次藍屏重啓後電腦着火
這裏寫圖片描述

確保類的唯一性,使得同類名的類可以同時存在,使用包進行劃分。
權限問題:
這裏寫圖片描述

規則

    1、包必須寫在程序的第一行。因爲要先有包,才知道類文件的存放地方。

    2、類的全稱:包名.類名。

    3、編譯定義了包的程序文件時,在編譯時要指定包的存儲目錄。

   如:javac –d c:\mypack類名.java

jar包

創建jar包

            jar  -cvf  mypack.jar packa packb

查看jar包

            jar  -tvf  mypack.jar  [>定向文件]

解壓縮

            jar  -xvf  mypack.jar

自定義jar包的清單文件

            jar –cvfm  mypack.jar mf.txt  packa packb

單個包打成jar包:

這裏寫圖片描述

進入cmd:
這裏寫圖片描述

編譯:
這裏寫圖片描述
javac -d . Demo.java和javac -d f:\JavaDemo Demo.java的不同在於指定的目錄不同。

jar包生成:
這裏寫圖片描述

運行:把生成的jar包放到D盤下,設置classpath路徑,並運行。
這裏寫圖片描述

多個不同包下的類建jar包:
同理:javac –d . Demo.java分別編譯
這裏寫圖片描述
建好後:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章