10.Java異常問題

瀟湘劍雨發表於2018-12-26

目錄介紹

  • 10.0.0.1 見過哪些執行時異常?異常處理機制知道哪些?從異常是否必須需要被處理的角度來看怎麼分類?
  • 10.0.0.2 運用Java異常處理機制?異常處理的原理?Java中檢查異常和非檢查異常的區別?
  • 10.0.0.3 異常處理的過程中,你遵循那些好的實踐? throw 和 throws這兩個關鍵字在java中有什麼不同?
  • 10.0.0.4 你知道什麼是“異常鏈”嗎?自定義實現過哪些異常,怎麼寫的?可以有一個空的catch塊嗎?
  • 10.0.0.5 Java異常類有哪些的重要方法?導致“主執行緒中的異常”的不同場景是什麼?
  • 10.0.0.6 看下面這段子類繼承父類程式碼有什麼問題?針對拋異常是IOException還是Exception,能隨便寫嗎,結合案例說一下?
  • 10.0.0.7 捕獲異常時,為何在catch中要注意異常層級關係?需要注意哪些問題?

好訊息

  • 部落格筆記大彙總【15年10月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連結地址:https://github.com/yangchong211/YCBlogs
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!所有部落格將陸續開源到GitHub!

10.0.0.1 見過哪些執行時異常?異常處理機制知道哪些?從異常是否必須需要被處理的角度來看怎麼分類?

  • 執行時異常:Throwable繼承層次結構,可見分成兩大類Error和Exception:

    • Error(錯誤):指程式無法恢復的異常情況,表示執行應用程式中較嚴重的問題;發生於虛擬機器自身、或者在虛擬機器試圖執行應用時,如Virtual MachineError(Java虛擬機器執行錯誤)、NoClassDefFoundError(類定義錯誤);屬於不可查異常,即不強制程式設計師必須處理,即使不處理也不會出現語法錯誤。
    • Exception(異常):指程式有可能恢復的異常情況,表示程式本身可以處理的異常。又分兩大類:

      • RuntimeException(執行時異常):由程式自身的問題導致產生的異常;如NullPointerException(空指標異常)、IndexOutOfBoundsException(下標越界異常);屬於不可查異常。
      • 非執行時異常:由程式外部的問題引起的異常;除了RuntimeException以外的異常,如FileNotFoundException(檔案不存在異常);屬於可查異常,即強制程式設計師必須進行處理,如果不進行處理則會出現語法錯誤。
  • 異常處理機制

    • 捕捉異常:由系統自動丟擲異常,即try捕獲異常->catch處理異常->finally 最終處理
    • 丟擲異常:在方法中將異常物件顯性地丟擲,之後異常會沿著呼叫層次向上丟擲,交由呼叫它的方法來處理。配合throws宣告丟擲的異常和throw丟擲異常
    • 自定義異常:繼承Execption類或其子類
    • 技術部落格大總結
  • 從異常是否必須需要被處理的角度來看怎麼分類

    • 異常又可分為不受檢查異常和受檢查異常兩種情況:

      • 不受檢查異常:派生於 Error 或 RuntimeException 的所有異常;
      • 受檢查異常:除去不受檢查異常的所有異常。
      • image

10.0.0.2 運用Java異常處理機制? 異常處理的原理?Java中檢查異常和非檢查異常的區別?

  • 運用Java異常處理機制?

    • 1.try…catch語句
    • 2.finally語句:大多數情況下都必須執行的程式碼
    • 3.throws子句:宣告可能發生的異常類
    • 4.throw:丟擲具體的異常物件。
  • 異常處理的原理?

    • Java虛擬機器用方法呼叫棧(method invocation stack)來跟蹤每個執行緒中一系列的方法呼叫過程。如果在執行方法過程中丟擲異常,則Java虛擬機器必須找到能捕獲該異常的catch程式碼塊。當Java虛擬機器追溯到呼叫棧的底部的方法的時候,如果仍然沒有找到處理該異常的程式碼塊,這樣它就會按步驟處理,首先會列印方法呼叫棧的異常資訊,然後如果所處的執行緒不是主執行緒,那麼就會終止這個執行緒。
  • Java中檢查異常和非檢查異常的區別

    • 檢查型異常(CheckedException)

      • 在Java中所有不是RuntimeException派生的Exception都是檢查型異常。當函式中存在丟擲檢查型異常的操作時該函式的函式宣告中必須包含throws語句。呼叫改函式的函式也必須對該異常進行處理,如不進行處理則必須在呼叫函式上宣告throws語句。
      • 檢查型異常是JAVA首創的,在編譯期對異常的處理有強制性的要求。在JDK程式碼中大量的異常屬於檢查型異常,包括IOException,SQLException等等。
    • 非檢查型異常(UncheckedException)技術部落格大總結

      • 在Java中所有RuntimeException的派生類都是非檢查型異常,與檢查型異常對比,非檢查型異常可以不在函式宣告中新增throws語句,呼叫函式上也不需要強制處理。
      • 常見的NullPointException,ClassCastException是常見的非檢查型異常。非檢查型異常可以不使用try…catch進行處理,但是如果有異常產生,則異常將由JVM進行處理。對於RuntimeException的子類最好也使用異常處理機制。雖然RuntimeException的異常可以不使用try…catch進行處理,但是如果一旦發生異常,則肯定會導致程式中斷執行,所以,為了保證程式再出錯後依然可以執行,在開發程式碼時最好使用try…catch的異常處理機制進行處理。

10.0.0.3 異常處理的過程中,你遵循那些好的實踐? throw 和 throws這兩個關鍵字在java中有什麼不同?

  • 異常處理的過程中,你遵循那些好的實踐?

    • 異常處理在專案設計中是非常關鍵的,所以精通異常處理是十分必要的。異常處理有很多最佳實踐,下面列舉集中,它們提高你程式碼的健壯性和靈活性:
    • 1) 呼叫方法的時候返回布林值來代替返回null,這樣可以 NullPointerException。由於空指標是java異常裡最噁心的異常。
    • 2) catch塊裡別不寫程式碼。空catch塊是異常處理裡的錯誤事件,因為它只是捕獲了異常,卻沒有任何處理或者提示。通常你起碼要列印出異常資訊,當然你最好根據需求對異常資訊進行處理。
    • 3)能拋受控異常(checked Exception)就儘量不拋受非控異常(checked Exception)。通過去掉重複的異常處理程式碼,可以提高程式碼的可讀性。
    • 4) 絕對不要讓你的資料庫相關異常顯示到客戶端。由於絕大多數資料庫和SQLException異常都是受控異常,在Java中,你應該在DAO層把異常資訊處理,然後返回處理過的能讓使用者看懂並根據異常提示資訊改正操作的異常資訊。
    • 5) 在Java中,一定要在資料庫連線,資料庫查詢,流處理後,在finally塊中呼叫close()方法。
  • throw 和 throws這兩個關鍵字在java中有什麼不同?

    • 技術部落格大總結
    • throws總是出現在一個函式頭中,用來標明該成員函式可能丟擲的各種異常,你也可以申明未檢查的異常,但這不是編譯器強制的。如果方法丟擲了異常那麼呼叫這個方法的時候就需要將這個異常處理。
    • throw 是用來丟擲任意異常的,按照語法你可以丟擲任意 Throwable (Throwable 或任何Throwable的衍生類) , throw可以中斷程式執行,因此可以用來代替return。
    private static voidshow() {  
        throw new UnsupportedOperationException(“丟擲異常”);
    }

10.0.0.4 你知道什麼是“異常鏈”嗎?自定義實現過哪些異常,怎麼寫的?可以有一個空的catch塊嗎?

  • 你知道什麼是“異常鏈”嗎?

    • “異常鏈”是Java中非常流行的異常處理概念,是指在進行一個異常處理時丟擲了另外一個異常,由此產生了一個異常鏈條。該技術大多用於將“ 受檢查異常” ( checked exception)封裝成為“非受檢查異常”(unchecked exception)或者RuntimeException。順便說一下,如果因為因為異常你決定丟擲一個新的異常,你一定要包含原有的異常,這樣,處理程式才可以通過getCause()和initCause()方法來訪問異常最終的根源。
  • 自定義實現過哪些異常?
  • 可以有一個空的catch塊嗎?

    • 可以有一個空的catch塊,但這是最糟糕的程式設計的例子。不應該有空的catch塊,因為如果異常被該塊捕獲,我們將沒有關於異常的資訊,它將成為除錯它的噩夢。應該至少有一個日誌記錄語句來記錄控制檯或日誌檔案中的異常詳細資訊。
    • 技術部落格大總結

10.0.0.5 Java異常類有哪些的重要方法?導致“主執行緒中的異常”的不同場景是什麼?

  • Java異常類有哪些的重要方法?

    • Exception和它的所有子類沒有提供任何特殊方法供使用,它們的所有方法都是來自其基類Throwable。

      • String getMessage():方法返回Throwable的String型資訊,當異常通過構造器建立後可用。
      • String getLocalizedMessage():此方法通過被重寫來得到用本地語言表示的異常資訊返回給呼叫程式。Throwable類通常只是用getMessage()方法來實現返回異常資訊。
      • synchronized Throwable getCause():此方法返回異常產生的原因,如果不知道原因的話返回null。(原文有拼寫錯誤 應該是if 不是id)
      • String toString():方法返回String格式的Throwable資訊,此資訊包括Throwable的名字和本地化資訊。
      • void printStackTrace():該方法列印棧軌跡資訊到標準錯誤流。該方法能接受PrintStream 和PrintWriter作為引數實現過載,這樣就能實現列印棧軌跡到檔案或流中。
  • 導致“主執行緒中的異常”的不同場景是什麼?

    • 一些常見的主執行緒異常情況是:

      • 執行緒main java.lang.UnsupportedClassVersionError中的異常:當您的java類從另一個JDK版本編譯並且您試圖從另一個java版本執行它時,會出現此異常。
      • 執行緒main java.lang.NoClassDefFoundError中的異常 :此異常有兩種變體。 第一個是你提供副檔名為.class的類全名的地方。 第二種情況是沒有找到類。
      • 執行緒main java.lang.NoSuchMethodError中的異常:main :當您嘗試執行一個沒有main方法的類時,會出現此異常。
      • 技術部落格大總結
      • 執行緒“main”中的異常java.lang.ArithmeticException :無論何時從main方法丟擲任何異常,它都會列印出異常是console。 第一部分解釋了異常從main方法丟擲,第二部分列印異常類名稱,然後在冒號後列印異常訊息。

10.0.0.6 看下面這段子類繼承父類程式碼有什麼問題?針對拋異常是IOException還是Exception,能隨便寫嗎,結合案例說一下?

  • 看下面這段程式碼有什麼問題?

    public class SuperClass {  
        public void start() throws IOException{
            throw new IOException("Not able to open file");
        }
    }
     
    public class SubClass extends SuperClass{  
        public void start() throws Exception{
            throw new Exception("Not able to start");
        }
    }
    • 這段程式碼編譯器將對子類覆蓋start方法產生錯誤。因為每個Java中方法的覆蓋是有規則的,一個覆蓋的方法不能丟擲的異常比原方法繼承關係高。因為這裡的start方法在超類中丟擲了IOException,所有在子類中的start方法只能丟擲要麼是IOExcepition或是其子類,但不能是其超類,如Exception。
  • 針對拋異常是IOException還是Exception,能隨便寫嗎,結合案例說一下?

    • 肯定不要隨便寫,容易造成迷惑性。下面看看程式碼,舉個簡單的案例!技術部落格大總結
    public static void start(){
       System.out.println("Java Exception");
    }
     
    public static void main(String args[]) {
       try{
          start();
       }catch(IOException e){
          e.printStackTrace();
       }
    }
    • 上面的Java異常例子程式碼中,編譯器將在處理IOException時報錯,因為IOException是受檢查異常,而start方法並沒有丟擲IOException,所以編譯器將丟擲“異常,java.io.IOException不會在try語句體中丟擲”,但是如果你將IOException改為Exception,編譯器報錯將消失,因為Exception可以用來捕捉所有執行時異常,這樣就不需要宣告丟擲語句。我喜歡這樣帶有迷惑性的Java異常面試題,因為它不會讓人輕易的找出是IOException還是Exception。你也可以在JoshuaBloach和NeilGafter的Java謎題中找到一些有關Java錯誤和異常的具有迷惑性問題。

10.0.0.7 捕獲異常時,為何在catch中要注意異常層級關係?需要注意哪些問題?

  • 捕獲異常時,為何在catch中要注意異常層級關係?需要注意哪些問題?

    • 注意,catch中一定要注意層級關係。這裡舉一個簡單的案例,就可以很好的理解為何要注重層級問題呢!
    • 技術部落格大總結
    public static void start() throws IOException, RuntimeException{
        throw new RuntimeException("Not able to Start");
    }
    
    public static void main(String args[]) {
        try {
            start();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (RuntimeException e2) {
            e2.printStackTrace();
        }
    }
    • 這段程式碼會在捕捉異常程式碼塊的RuntimeException型別變數“e2”裡丟擲編譯異常錯誤。因為Exception是RuntimeException的超類,在start方法中所有的RuntimeException會被第一個捕捉異常塊捕捉,這樣就無法到達第二個捕捉塊,這就是丟擲“exception java.lang.RuntimeException has already been caught”的編譯錯誤原因。

其他介紹

01.關於部落格彙總連結

02.關於我的部落格


相關文章