1. 程式人生 > 其它 >Java 語言-7 Java 基礎語法 3.0

Java 語言-7 Java 基礎語法 3.0

7.1 異常機制

7.1.1 認識異常

  • 異常(exception)又稱例外、差錯、違例

    • 對應 Java 執行錯誤處理機制
  • 簡單分類

    • 檢查性異常:這是程式設計師不可預知的異常,最具代表性的檢查性錯誤是使用者錯誤或問題引起的異常,這些異常在編譯時不能被簡單的忽略
    • 執行時異常:這是程式設計師可以避免的異常
    • 錯誤(Error):錯誤並不是異常,而脫離程式設計師控制的問題。在程式碼中通常被忽略
  • 傳統語言(例如:C 語言)處理異常

    • 方式:
      • if 語句判斷是否出現異常
      • 全程使用變數 ErroNo 記錄異常
    • 缺點:
      1. 可讀性差。正常處理與異常處理的程式碼進行同樣的處理
      2. 可維護性差。每次呼叫一個方法時都進行錯誤檢查
      3. 職責不清。錯誤由誰處理分辨不清
  • Java 的異常處理

    • 丟擲(throw)異常
    • 執行時系統在呼叫棧中查詢
      • 從生成異常的方法開始回溯直到找到
    • 捕獲(catch)異常程式碼
  • Java 異常體系結構

    • Java 將異常當作物件處理,定義了一個基類 java.lang.Throwable 作為所有異常的超類
    • 在 Java API 中將定義的許多異常類通常分為兩大類,錯誤(Error)和異常(Exception),一般說的異常是指 Exception 及其子類
  • Error & Exception

    • Error 類物件由 Java 虛擬機器(JVM)生成並丟擲,大多數錯誤與程式碼編寫者所執行的操作無關
      • 大多數時 Java 虛擬機器執行錯誤(Virtual MachineError),還有虛擬機器企圖執行應用時
      • 這些錯誤是不可查的,因為這些錯誤是在應用程式的控制和處理之外,而且絕大數是程式執行時不允許出現的狀況
    • Exception
      • 在 Exception 中有一個重要的子類 RuntimeException(執行時異常),這些異常一般是由程式邏輯錯誤引起。程式應該從邏輯角度儘可能避免這類異常的發生
    • 二者區別:
      • Error 通常是災難級的致命錯誤,是程式無法控制和處理的當出現這些異常,Java 虛擬機器一般會選擇終止執行緒
      • Exception 通常情況下可以被程式處理,並且在程式中應該儘可能的去處理這些異常
  • Exception 類

    • 構造方法的三種形式:

      public Exception();
      public Exception(String message);
      public Exception(String message,Throwable cause);
      
    • 常見讀取方式:

      • getMessage():獲取異常資訊
      • getCause():獲取內部原因
      • printStackTrace():輸出呼叫棧的跟蹤資訊,即 IDEA 輸出的異常資訊

7.1.2 處理異常

  • 處理異常的五個關鍵字

    • try、catch、finally、throw、throws

      try-catch:捕獲異常。try:監控區域;catch:捕獲異常。

      finally:處理善後工作。無論是否經過 try-catch 都會執行 finally 語句。多用於 IO 的資源關閉

      throw 和 throws:丟擲異常物件。throw 在方法中使用;throws 在宣告方法時使用

  • 基本寫法:try-catch

    try{
        ……
    }catch(Exception e){
        ……
    }finally{
        ……
    }
    

    catch 語句可以有 0 到多個

    finally 語句可以有 0 到 1 個

    • 多異常的處理:子類異常要排在父類異常前
  • 快捷鍵(IDEA):Crtl+Alt+T

  • 主動丟擲異常:當已知程式碼有問題,用 throw 主動丟擲異常,主動結束程式碼

    • 一般在方法中使用

    • 例如:

      public void test(int a;int b){
          if (b==0){
              throw new ArithmeticException();
          }
      }
      
  • 在方法上丟擲異常使用 throws

    • 例如:

      public void test(int a;int b) throws ArithmeticException{
          if (b==0){
              throw new ArithmeticException();
          }
      }
      
  • 重拋異常:其中對於異常,不僅需要進行捕獲處理,有時候還需要將異常進一步傳遞給呼叫者

  • 方法:

    1. 將當前捕獲的異常再次丟擲,如:throw e;
    2. 重新生成異常並丟擲,如:throw new Exception("some message");
    3. 重新生成並丟擲一個新異常,該異常包含了當前異常的資訊,如:throw new Exxception("some message",e);
      • 這種方式可用 e.getCause() 來得到內部異常

7.1.3 自定義異常

  • 用的不多,Java 自帶的異常就非常多了,而且還有很多開源的異常在網上,所有一般都不需要自定義異常

  • 大體方法:自定義異常類只需要繼承 Exception 類即可

  • 大體步驟:

    1. 建立自定義異常類
    2. 在方法體中通過 throw 關鍵字丟擲異常物件
      • 如果在當前丟擲異常的方法中處理異常,可以使用 try-catch 捕獲異常並處理
      • 如果不在當前方法中處理,則需要在方法的宣告處使用 throws 關鍵字指明需要丟擲給方法呼叫者的異常
    3. 在出現異常方法的呼叫者中捕獲處理異常
  • 如果仍然不知道怎樣寫,可以檢視 Java 自帶的異常方法,作為案例

  • 示例:定義一個輸入大於10的數就丟擲異常的自定義異常類

    定義自定義異常類 MyException

    package exercise.DivMyException;
    
    public class MyException extends Exception{
        //傳遞數字>10
        private int detail;
    
        public MyException(int a) {
            this.detail =a;
        }
    
        //toString:異常的列印資訊
        @Override
        public String toString() {
            return "MyException{" +
                    "detail=" + detail +
                    '}';
        }
    }
    

    定義測試自定義異常類 Test

    package exercise.DivMyException;
    
    import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
    
    public class Test {
        //可能存在異常的方法
        static void test(int a) {
    
            System.out.println("傳遞引數為:"+a);
    
            if(a>10){
                try {
                    throw new MyException(a);
                } catch (MyException e) {
                    System.out.println("MyException:"+e);
                }
    
            }else {
                System.out.println("OK");
            }
    
        }
        public static void main(String[] args) {
            test(1);
        }
    }
    

    測試結果:

    傳遞引數為:1
    OK
    
    傳遞引數為:10
    OK
    
    傳遞引數為:11
    MyException:MyException{detail=11}
    
  • 實際經驗總結

    • 處理執行時異常時,採用邏輯去合理規避同時採用 try-catch 輔助處理
    • 在多重 catch 塊後面,可以加入 catch(Exception) 來處理可能會被遺漏的的異常
    • 對於不確定的程式碼,也可以使用 try-catch 處理潛在的異常
      • 在 IDEA 中潛藏的異常會以波浪線標紅,可以使用alt+Enter檢視提示資訊
    • 處理異常時,儘量細緻的去處理異常,切忌只是簡單呼叫 printStackTrace() 去列印輸出
    • 具體如何處理異常,需要根據不同的業務需求和異常型別去決定
    • 處理過程中,儘量新增 finally 語句去釋放佔用的資源
      • 特別是 IO、Scanner

7.2 類、介面等完整定義

  • 如果看不懂個別意思,可能是因為沒學習到;如果基本都沒看懂,就是前面沒有學習紮實

  • 完整類定義

    //類宣告
    [public][abstract | final] class className [extends superclassName][implements InterfaceName]{
        //成員變數宣告,可為多個
        [public | protected | private][static][final][transient][volatile] type variableName;
        //方法定義,可為多個
        [public | protected | private][static][final | abstract][native][synchronized] returnType methodName ([paramList])
            //方法實現,可為多個
            [throws exceptionList]{
            statements
        } 
    }
    
  • 完整介面定義

    //介面宣告
    [public] interface InterfaceName [extends superInterfaceList]{
        //常量宣告,可為多個
        type constantName = Value;
        //方法宣告,可為多個
        returnType methodName([paramList]);
    }
    

    未加入 jdk 8 以後新加的定義方法

  • 三種方法固定的宣告方式

    1. 構造方法:

      calssName([paramList]){
          ……
      }
      
    2. main() 方法:

      public static void main(String[] args){
          ……
      }
      
    3. finalize() 方法:

      protected void finalize() throws throwable{
          ……
      }
      

      幾乎不用的

  • 完整 Java 原始檔

    //指定檔案中類所在包
    package packageName;
    //指定引入的類
    import packageName.[className | *];
    //屬性為 public 的類定義
    public classDefinition
    //介面或者類的定義
    interfaceDefinition and classDefinition
    

    原始檔名字必須與屬性為 public 的類的類名一致