溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java中重要的錯誤處理機制異常有哪些

發(fā)布時間:2021-10-18 14:10:28 來源:億速云 閱讀:129 作者:iii 欄目:編程語言

這篇文章主要介紹“Java中重要的錯誤處理機制異常有哪些”,在日常操作中,相信很多人在Java中重要的錯誤處理機制異常有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中重要的錯誤處理機制異常有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習吧!

一、異常介紹

什么是異常?

異常是指程序在運行過程中發(fā)生的,由于外部問題導(dǎo)致的程序運行異常事件,異常的發(fā)生往往會中斷程序的運行。在 Java  這種面向?qū)ο蟮木幊陶Z言中,萬物都是對象,異常本身也是一個對象,程序發(fā)生異常就會產(chǎn)生一個異常對象。

異常的分類

Throwable

從圖中可以看到,異常主要有以下類構(gòu)成:

  • Throwable

  • Error

  • Exception

接下來我們就分別介紹一下這幾個基類的作用。

Throwable

Throwable 類是 Java  語言中所有錯誤或異常的頂層父類,其他異常類都繼承于該類。Throwable類有兩個重要的子類:**Exception(異常)**和  「Error(錯誤)」,二者都是 Java 異常處理的重要子類,各自都包含大量子類。

只有當對象是此類或其子類的實例時,才能通過 Java 虛擬機或者 Java throw 語句拋出。類似地,只有此類或其子類才可以是 catch  子句中的參數(shù)類型。

Throwable 對象中包含了其線程創(chuàng)建時線程執(zhí)行堆棧的快照,它還包含了給出有關(guān)錯誤更多信息的消息字符串。

最后,它還可以包含 cause(原因):另一個導(dǎo)致此 throwable 拋出的 throwable。此 cause 設(shè)施在 1.4  版本中首次出現(xiàn)。它也稱為異常鏈設(shè)施,因為 cause 自身也會有 cause,依此類推,就形成了異常鏈,每個異常都是由另一個異常引起的。

Error

Error 是 Throwable 的子類,通常情況下應(yīng)用程序「不應(yīng)該試圖捕獲的嚴重問題」。

Error 是程序無法處理的錯誤,表示運行應(yīng)用程序中較嚴重問題。大多數(shù)錯誤與代碼編寫者執(zhí)行的操作無關(guān),而表示代碼運行時 JVM(Java  虛擬機)出現(xiàn)的問題。

例如:Java虛擬機運行錯誤(Virtual MachineError),當 JVM 不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時,將出現(xiàn)  OutOfMemoryError。這些異常發(fā)生時,Java虛擬機(JVM)一般會選擇線程終止。

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

Exception

Exception以及它的子類,代表程序運行時發(fā)送的各種不期望發(fā)生的事件??梢员籎ava異常處理機制使用,是異常處理的核心。

Exception 異常主要分為兩類:

「1、非檢查性異常(unchecked exception)」

Error 和 RuntimeException  以及他們的子類。Java語言在編譯時,不會提示和發(fā)現(xiàn)這樣的異常,不要求在程序中處理這些異常。所以我們可以在程序中編寫代碼來處理(使用try…catch…finally)這樣的異常,也可以不做任何處理。對于這些錯誤或異常,我們應(yīng)該修正代碼,而不是去通過異常處理器處理。這樣的異常發(fā)生的原因多半是由于我們的代碼邏輯出現(xiàn)了問題。

例如:

  • 當程序中用數(shù)字除以0時,就會拋出ArithmeticException異常;

  • 在類型轉(zhuǎn)換時,錯誤的強制類型轉(zhuǎn)換會拋出ClassCastException類型轉(zhuǎn)換異常;

  • 當使用集合進行數(shù)組索引越界時就會拋出ArrayIndexOutOfBoundsException異常;

  • 當程序中使用了空對象進行操作時就會拋出注明的空指針NullPointerException異常等。

「常見的非檢查性異常有」:

異常描述
ArithmeticException當出現(xiàn)異常的運算條件時,拋出異常。例如,一個整數(shù)“除以零”時,拋出此類的一個實例。
ArrayIndexOutOfBoundsException用非法索引訪問數(shù)組時跑出的異常。如果索引為負或大于等于數(shù)組大小,則該索引為非法索引。
ArrayStoreException試圖將錯誤類型的對象存儲到一個對象數(shù)組時,拋出的異常。
ClassCastException試圖將對象強制轉(zhuǎn)換為不是同一個類型或其子類的實例時,拋出的異常。
IllegalArgumentException當向一個方法傳遞非法或不正確的參數(shù)時,拋出該異常。
IllegalMonitorStateException當某一線程已經(jīng)試圖等待對象的監(jiān)視器,或者通知其他正在等待該對象監(jiān)視器的線程,而該線程本身沒有獲得指定監(jiān)視器時拋出該異常。
IllegalStateException在非法或不適當?shù)臅r間調(diào)用方法時產(chǎn)生的信號?;蛘哒fJava環(huán)境或應(yīng)用程序沒有處于請求操作所要求的適當狀態(tài)下。
IllegalThreadStateException線程沒有處于請求操作所要求的適當狀態(tài)時,拋出該異常。
IndexOutOfBoundsException當某種排序的索引超出范圍時拋出的異常,例如,一個數(shù)組,字符串或一個向量的排序等。
NegativeArraySizeException如果應(yīng)用程序試圖創(chuàng)建大小為負的數(shù)組時,拋出該異常。
NullPointerException當應(yīng)用程序在需要操作對象的時候而獲得的對象實例是null時拋出該異常。
NumberFormatException當應(yīng)用程序試圖將字符串轉(zhuǎn)換成一種數(shù)值類型,但該字符串不能轉(zhuǎn)換為適當格式時,拋出該異常。
SecurityException由安全管理器拋出的異常,指示存在安全侵犯。
StringIndexOutOfBoundsException此異常由String方法拋出,說明索引為負或者超出了字符串的大小。

「2、檢查性異常(checked exception)」

除了Error 和  RuntimeException的其它異常。Java語言強制要求程序員為這樣的異常做預(yù)備處理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch語句捕獲它并處理,要么用throws子句聲明拋出它,否則編譯不會通過。這樣的異常一般是由程序的運行環(huán)境導(dǎo)致的。因為程序可能被運行在各種未知的環(huán)境下,而程序員無法干預(yù)用戶如何使用他編寫的程序,于是程序員就應(yīng)該為這樣的異常時刻準備著。如SQLException,IOException,ClassNotFoundException  等。

檢查性異常就是指,編譯器在編譯期間要求必須得到處理的那些異常,你必須在編譯期處理了。

「常見的檢查性異常有」:

異常描述
ClassNotFoundException當應(yīng)用程序試圖加載一個類,通過名字查找時卻發(fā)現(xiàn)沒有該類的定義時,拋出該異常。
CloneNotSupportedException當去克隆一個對象時,發(fā)現(xiàn)該對象沒有實現(xiàn)Cloneable接口時,拋出該異常。
IllegalAccessException當應(yīng)用程序嘗試通過反射的方式來訪問類、成員變量或調(diào)用方法時,卻無法訪問這些類、成員變量或方法的定義時,拋出該異常。
InstantiationException當試圖使用Class類中的newInstance方法創(chuàng)建一個類的實例,而制定的類對象因為是一個接口或是一個抽象類而無法實例化時,拋出該異常。
InterruptedException一個線程被另一個線程中斷時,拋出該異常。
NoSuchFieldException當找不到指定的變量字段時,拋出該異常、
NoSuchMethodException當找不到指定的類方法時,拋出該異常。

二、初識異常

下面我們通過一個簡單實例,讓大家更直觀的認識一下Java的異常。

下面的代碼會拋出著名的空指針異常:NullPointerException。

public class Test {     private int a = 1;     private int b = 2;      public static void main(String[] args) {         Test t1 = new Test();         Test t2 = null;         System.out.println(t1.a);         System.out.println(t2.a);         System.out.println(t2.c());     }      public String c() {         return "微信公眾號:我是開發(fā)者FTD";     } }

運行程序,控制臺輸出結(jié)果如下:

1 Exception in thread "main" java.lang.NullPointerException  at cc.devclub.ftd.Test.main(Test.java:11)  Process finished with exit code 1

從控制臺輸出可以看到,程序打印了 “1”,然后在程序的第11行的位置拋出了 「java.lang.NullPointerException」  ,然后程序就終止運行了。

三、異常處理機制

在編寫代碼處理異常時,對于檢查性異常,有兩種不同的處理方式:

  • 使用 「try…catch…finally…」 語句塊處理

  • 在方法中使用 「throws/throw」 關(guān)鍵詞將異常交給方法調(diào)用者去處理

try...catch...finally… 關(guān)鍵字

  • 使用 try 和 catch 關(guān)鍵字可以捕獲異常。

  • try/catch 代碼塊放在異常可能發(fā)生的地方。

try/catch代碼塊中的代碼稱為保護代碼,使用 try/catch 的語法如下:

try {     ... } catch (IOException ioException) {     ... } catch (Exception exception) {     ... } finally {     ... }

「try 塊:」

  • try塊中放可能發(fā)生異常的代碼。

  • 如果執(zhí)行完try且不發(fā)生異常,則接著去執(zhí)行finally塊中的代碼和finally后面的代碼(如果有的話)。

  • 如果程序發(fā)生異常,則嘗試去匹配對應(yīng)的catch塊。

「catch 塊:」

  • 每一個catch塊用于捕獲并處理一個特定的異常,或者這異常類型的子類。Java7中可以將多個異常聲明在一個catch中。

  • catch后面的括號定義了異常類型和異常參數(shù)。如果異常與之匹配且是最先匹配到的,則虛擬機將使用這個catch塊來處理異常。

  • 在catch塊中可以使用這個塊的異常參數(shù)來獲取異常的相關(guān)信息。異常參數(shù)是這個catch塊中的局部變量,其它塊不能訪問。

  • 如果當前try塊中發(fā)生的異常在后續(xù)的所有catch中都沒捕獲到,則先去執(zhí)行finally,然后到這個方法的外部調(diào)用者中去匹配異常處理器。

  • 如果try中沒有發(fā)生異常,則所有的catch塊將被忽略。

「需要注意的地方」

1、try塊中的局部變量和catch塊中的局部變量(包括異常變量),以及finally中的局部變量,他們之間不可共享使用。

2、每一個catch塊用于處理一個異常。異常匹配是按照catch塊的順序從上往下尋找的,只有第一個匹配的catch會得到執(zhí)行。匹配時,不僅運行精確匹配,也支持父類匹配,因此,如果同一個try塊下的多個catch異常類型有父子關(guān)系,應(yīng)該將子類異常放在前面,父類異常放在后面,這樣保證每個catch塊都有存在的意義。

3、Java中,異常處理的任務(wù)就是將執(zhí)行控制流從異常發(fā)生的地方轉(zhuǎn)移到能夠處理這種異常的地方去。也就是說:當一個方法的某條語句發(fā)生異常時,這條語句的后面的語句不會再執(zhí)行,它失去了焦點。執(zhí)行流跳轉(zhuǎn)到最近的匹配的異常處理catch代碼塊去執(zhí)行,異常被處理完后,執(zhí)行流會接著在“處理了這個異常的catch代碼塊”后面接著執(zhí)行。

「finally 塊:」

  • finally塊不是必須的,通常是可選的。

  • 無論異常是否發(fā)生,異常是否匹配被處理,finally中的代碼都會執(zhí)行。

  • 一個try至少要有一個catch塊,否則,  至少要有1個finally塊。但是finally不是用來處理異常的,finally不會捕獲和處理異常,處理異常的只能是catch塊。

  • finally主要做一些清理工作,如流的關(guān)閉,數(shù)據(jù)庫連接的關(guān)閉等。

  • finally塊不管異常是否發(fā)生,只要對應(yīng)的try執(zhí)行了,則它一定也執(zhí)行。只有一種方法讓finally塊不執(zhí)行:「System.exit()」 。

大家需要養(yǎng)成**良好的編程習慣是:**在try塊中打開資源,在finally塊中清理并釋放這些資源,以免造成內(nèi)存泄露。

「需要注意的地方:」

1、在同一try…catch…finally…塊中,如果try中拋出異常,且有匹配的catch塊,則先執(zhí)行catch塊,再執(zhí)行finally塊。如果沒有catch塊匹配,則先執(zhí)行finally,然后去到上層的調(diào)用者中尋找合適的catch塊。

2、在同一try…catch…finally…塊中  ,try發(fā)生異常,且匹配的catch塊中處理異常時也拋出異常,那么后面的finally也會執(zhí)行:首先執(zhí)行finally塊,然后去上層調(diào)用者中尋找合適的catch塊。

throws/throw 關(guān)鍵字

  • 「throws 關(guān)鍵字」

如果一個方法內(nèi)部的代碼會拋出檢查性異常(checked  exception),而方法自己又沒有對這些異常完全處理掉,則java的編譯器會要求你必須在方法的簽名上使用 「throws」  關(guān)鍵字聲明這些可能拋出的異常,否則編譯不通過。

throws 是另一種處理異常的方式,它不同于try…catch…finally…,throws  關(guān)鍵字僅僅是將方法中可能出現(xiàn)的異常向調(diào)用者拋出,而自己則不具體處理。

采取這種異常處理的原因可能是:方法本身不知道如何處理這樣的異常,或者說讓調(diào)用者處理更好,調(diào)用者需要為可能發(fā)生的異常負責。

  • 「throw 關(guān)鍵字」

我們也可以通過 throw 語句手動顯式的拋出一個異常,throw語句的后面必須是一個異常對象。語法如下:

throw exceptionObject

throw 語句必須寫在方法中,執(zhí)行throw 語句的地方就是一個異常拋出點,它和由JRE自動形成的異常拋出點沒有任何差別。

public void save(User user) {     if (user == null)         throw new IllegalArgumentException("User對象為空");     //...... }

try-catch-finally 的執(zhí)行順序

try-catch-finally 執(zhí)行順序的相關(guān)問題可以說是各種面試中的「常客」了,尤其是 finally 塊中帶有 return  語句的情況。我們直接看幾道面試題:

「面試題一:」

public static void main(String[] args) {     int result = test1();     System.out.println(result); }  public static int test1() {     int i = 1;     try {         i++;         System.out.println("try block, i = " + i);     } catch (Exception e) {         i--;         System.out.println("catch block i = " + i);     } finally {         i = 10;         System.out.println("finally block i = " + i);     }     return i; }

大家不妨算一算程序員最終運行的結(jié)果是什么。

輸出結(jié)果如下:

try block, i = 2 finally block i = 10 10

這算一個相當簡單的問題了,沒有坑,下面我們稍微改動一下:

public static int test2() {     int i = 1;     try {         i++;         throw new Exception();     } catch (Exception e) {         i--;         System.out.println("catch block i = " + i);     } finally {         i = 10;         System.out.println("finally block i = " + i);     }     return i; }

輸出結(jié)果如下:

catch block i = 1 finally block i = 10 10

運行結(jié)果想必也是意料之中吧,程序拋出一個異常,然后被本方法的 catch 塊捕獲并進行了處理。

「面試題二:」

public static void main(String[] args) {     int result = test3();     System.out.println(result); }  public static int test3() {     //try 語句塊中有 return 語句時的整體執(zhí)行順序     int i = 1;     try {         i++;         System.out.println("try block, i = " + i);         return i;     } catch (Exception e) {         i++;         System.out.println("catch block i = " + i);         return i;     } finally {         i = 10;         System.out.println("finally block i = " + i);     } }

輸出結(jié)果如下:

try block, i = 2 finally block i = 10 2

是不是有點疑惑?明明我 try 語句塊中有 return 語句,可為什么最終還是執(zhí)行了 finally 塊中的代碼?

我們反編譯這個類,看看這個 test3 方法編譯后的字節(jié)碼的實現(xiàn):

0: iconst_1         //將 1 加載進操作數(shù)棧 1: istore_0         //將操作數(shù)棧 0 位置的元素存進局部變量表 2: iinc          0, 1   //將局部變量表 0 位置的元素直接加一(i=2) 5: getstatic     #3     // 5-27 行執(zhí)行的 println 方法                 8: new           #5                   11: dup 12: invokespecial #6                                                      15: ldc           #7  17: invokevirtual #8                                                      20: iload_0          21: invokevirtual #9                                                      24: invokevirtual #10                 27: invokevirtual #11                  30: iload_0         //將局部變量表 0 位置的元素加載進操作棧(2) 31: istore_1        //把操作棧頂?shù)脑卮嫒刖植孔兞勘砦恢?nbsp;1 處 32: bipush        10 //加載一個常量到操作棧(10) 34: istore_0        //將 10 存入局部變量表 0 處 35: getstatic     #3  //35-57 行執(zhí)行 finally中的println方法              38: new           #5                   41: dup 42: invokespecial #6                   45: ldc           #12                  47: invokevirtual #8                   50: iload_0 51: invokevirtual #9                 54: invokevirtual #10                  57: invokevirtual #11                  60: iload_1         //將局部變量表 1 位置的元素加載進操作棧(2) 61: ireturn         //將操作棧頂元素返回(2) -------------------try + finally 結(jié)束 ------------ ------------------下面是 catch + finally,類似的 ------------ 62: astore_1 63: iinc          0, 1 ....... .......

從我們的分析中可以看出來,finally 代碼塊中的內(nèi)容始終會被執(zhí)行,無論程序是否出現(xiàn)異常的原因就是,「編譯器會將 finally  塊中的代碼復(fù)制兩份并分別添加在 try 和 catch 的后面」。

可能有人會所疑惑,原本我們的 i 就被存儲在局部變量表 0 位置,而最后 finally 中的代碼也的確將 slot 0 位置填充了數(shù)值  10,可為什么最后程序依然返回的數(shù)值 2 呢?

仔細看字節(jié)碼,你會發(fā)現(xiàn)在 return 語句返回之前,虛擬機會將待返回的值壓入操作數(shù)棧,等待返回,即使 finally 語句塊對 i  進行了修改,但是待返回的值已經(jīng)確實的存在于操作數(shù)棧中了,所以不會影響程序返回結(jié)果。

「面試題三:」

public static int test4() {     //finally 語句塊中有 return 語句     int i = 1;     try {         i++;         System.out.println("try block, i = " + i);         return i;     } catch (Exception e) {         i++;         System.out.println("catch block i = " + i);         return i;     } finally {         i++;         System.out.println("finally block i = " + i);         return i;     } }

運行結(jié)果:

try block, i = 2 finally block i = 3 3

其實你從它的字節(jié)碼指令去看整個過程,而不要單單死記它的執(zhí)行過程。

Java中重要的錯誤處理機制異常有哪些

你會發(fā)現(xiàn)程序最終會采用 finally 代碼塊中的 return 語句進行返回,而直接忽略 try 語句塊中的 return 指令。

自定義異常

Java 的異常機制中所定義的所有異常不可能預(yù)見所有可能出現(xiàn)的錯誤,某些特定的情境下,則需要我們自定義異常類型來向上報告某些錯誤信息。

而自定義異常類型也是相當簡單的,你可以選擇繼承 Throwable,Exception  或它們的子類,甚至你不需要實現(xiàn)和重寫父類的任何方法即可完成一個異常類型的定義。

例如:

public class MyException extends RuntimeException{ }  public class MyException extends Exception{ }

按照國際慣例,自定義的異常應(yīng)該總是包含如下的構(gòu)造函數(shù):

  • 一個無參構(gòu)造函數(shù)

  • 一個帶有String參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。

  • 一個帶有String參數(shù)和Throwable參數(shù),并都傳遞給父類構(gòu)造函數(shù)

  • 一個帶有Throwable 參數(shù)的構(gòu)造函數(shù),并傳遞給父類的構(gòu)造函數(shù)。

下面是IOException類的完整源代碼,我們可以參考:

public class IOException extends Exception {     static final long serialVersionUID = 7818375828146090155L;      public IOException() {         super();     }      public IOException(String message) {         super(message);     }      public IOException(String message, Throwable cause) {         super(message, cause);     }      public IOException(Throwable cause) {         super(cause);     } }

異常的注意事項

1、當子類重寫父類的帶有  throws聲明的函數(shù)時,其throws聲明的異常必須在父類異常的可控范圍內(nèi)——用于處理父類的throws方法的異常處理器,必須也適用于子類的這個帶throws方法  。這是為了支持多態(tài)。

例如,父類方法throws 的是2個異常,子類就不能throws 3個及以上的異常。父類throws IOException,子類就必須throws  IOException或者IOException的子類。

2、Java程序可以是多線程的。每一個線程都是一個獨立的執(zhí)行流,獨立的函數(shù)調(diào)用棧。如果程序只有一個線程,那么沒有被任何代碼處理的異常  會導(dǎo)致程序終止。如果是多線程的,那么沒有被任何代碼處理的異常僅僅會導(dǎo)致異常所在的線程結(jié)束。

也就是說,Java中的異常是線程獨立的,線程的問題應(yīng)該由線程自己來解決,而不要委托到外部,也不會直接影響到其它線程的執(zhí)行。

異常使用時的常見錯誤

1、將異常直接顯示在頁面或客戶端

將異常直接打印在客戶端的例子屢見不鮮,一旦程序運行出現(xiàn)異常,默認情況下容器將異常堆棧信息直接打印在頁面上。從客戶角度來說,任何異常都沒有實際意義,絕大多數(shù)的客戶也根本看不懂異常信息,軟件開發(fā)也要盡量避免將異常直接呈現(xiàn)給用戶,一定要在前端展示層對異常進行封裝后展示。目前絕大多數(shù)應(yīng)用都是前后端分離的模式,這種直接打印異常的情況已經(jīng)相對改善了很多,不過我們在編碼時還是要特別注意下這個原則。

2、忽略異常

如下異常處理只是將異常輸出到控制臺,沒有任何意義。而且這里出現(xiàn)了異常并沒有中斷程序,進而調(diào)用代碼繼續(xù)執(zhí)行,導(dǎo)致更多的異常。

public void retrieveObjectById(Long id) {     try {         //..some code that throws SQLException     } catch (SQLException ex) {         /**           *了解的人都知道,這里的異常打印毫無意義,僅僅是將錯誤堆棧輸出到控制臺。           * 而在 Production 環(huán)境中,需要將錯誤堆棧輸出到日志。           * 而且這里 catch 處理之后程序繼續(xù)執(zhí)行,會導(dǎo)致進一步的問題*/          ex.printStacktrace();     } }

捕獲了異常缺不進行處理,這是我們在寫代碼時候的大忌,可以重構(gòu)成:

public void retrieveObjectById(Long id) {     try {         //..some code that throws SQLException     } catch (SQLException ex) {         throw new RuntimeException("Exception in retieveObjectById”, ex);     } finally {         //clean up resultset, statement, connection etc     } }

3、將異常包含在循環(huán)語句塊中

如下代碼所示,異常包含在 for 循環(huán)語句塊中。

for (int i = 0; i < 100; i++) {     try {     } catch (XXXException e) {         //....     } }

我們都知道異常處理占用系統(tǒng)資源。一看,大家都認為不會犯這樣的錯誤。換個角度,類 A 中執(zhí)行了一段循環(huán),循環(huán)中調(diào)用了 B 類的方法,B  類中被調(diào)用的方法卻又包含 try-catch 這樣的語句塊。褪去類的層次結(jié)構(gòu),代碼和上面如出一轍。

4、利用 Exception 捕捉所有潛在的異常

一段方法執(zhí)行過程中拋出了幾個不同類型的異常,為了代碼簡潔,利用基類 Exception 捕捉所有潛在的異常,如下例所示:

public void retrieveObjectById(Long id) {     try {         //...拋出 IOException 的代碼調(diào)用         //...拋出 SQLException 的代碼調(diào)用     } catch (Exception e) {         //這里利用基類 Exception 捕捉的所有潛在的異常,如果多個層次這樣捕捉,會丟失原始異常的有效信息         throw new RuntimeException("Exception in retieveObjectById”, e);     } }

估計大部分程序員都會有這種寫法,為了省事簡便,直接一個頂層的exception來捕獲所有可能出現(xiàn)的異常,這樣雖然可以保證異??隙〞徊蹲降?,但是程序卻無法針對不同的錯誤異常進行對應(yīng)正確的處理,可以重構(gòu)成:

public void retrieveObjectById(Long id) {     try {         //..some code that throws RuntimeException, IOException, SQLException     } catch (IOException e) {         //僅僅捕捉 IOException         throw new RuntimeException(/*指定這里 IOException 對應(yīng)的錯誤代碼*/code, "Exception in retieveObjectById”, e);     } catch (SQLException e) {         //僅僅捕捉 SQLException         throw new RuntimeException(/*指定這里 SQLException 對應(yīng)的錯誤代碼*/code, "Exception in retieveObjectById”, e);     } }

5、異常包含的信息不能充分定位問題

異常不僅要能夠讓開發(fā)人員知道哪里出了問題,更多時候開發(fā)人員還需要知道是什么原因?qū)е碌膯栴},我們知道 java .lang.Exception  有字符串類型參數(shù)的構(gòu)造方法,這個字符串可以自定義成通俗易懂的提示信息。

簡單的自定義信息開發(fā)人員只能知道哪里出現(xiàn)了異常,但是很多的情況下,開發(fā)人員更需要知道是什么參數(shù)導(dǎo)致了這樣的異常。這個時候我們就需要將方法調(diào)用的參數(shù)信息追加到自定義信息中。下例只列舉了一個參數(shù)的情況,多個參數(shù)的情況下,可以單獨寫一個工具類組織這樣的字符串。

public void retieveObjectById(Long id) {     try {         //..some code that throws SQLException     } catch (SQLException ex) {         //將參數(shù)信息添加到異常信息中         throw new RuntimeException("Exception in retieveObjectById with Object Id :"+ id, ex);     } }

到此,關(guān)于“Java中重要的錯誤處理機制異常有哪些”的學(xué)習就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習,快去試試吧!若想繼續(xù)學(xué)習更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI