天天看點

吃透JAVA中異常處理機制

JAVA中異常處理機制

任何程式都追求正确有效的運作,除了保證我們代碼盡可能的少出錯之外,我們還要考慮如何有效的處理異常,
	一個良好的異常架構對于系統來說是至關重要的。最近在給公司寫采集架構的時候系統的了解一邊,收獲頗多,特此記錄相關的理論。
           

1. 什麼是異常

異常就是程式在運作期間可能出現的各種異常不到的資訊、導緻程式不能正常的運作。
           

2. 異常的本質

異常的本質就是確定程式在運作期間能夠正常的運作、再出現異常的情況下能夠正确的關閉程式。
           

3. 異常的分類

JDK中定義了很多異常類、這些類對應着不同的各種可能出現異常資訊的事件、所有的異常對象都遠勝于Throwable類的一個執行個體、	
如果内置的異常類不能夠滿足需要、還可以自己建立異常java對異常進行了分類處理、不同的異常分别有着不同的java類表示、
所有的異常根類是屬于java.lang.Throwable Throwable下面有派生出兩個子類 Error  和  Exception 
           

體系結構圖:

吃透JAVA中異常處理機制

4. Error和Exception的了解

4.1、Error:(錯誤):是程式中無法處理的錯誤,表示運作應用程式中出現了嚴重的錯誤。此類錯誤一般表示代碼運作時JVM出現問題。
通常有Virtual MachineError(虛拟機運作錯誤)、NoClassDefFoundError(類定義錯誤)等。
比如說當jvm耗完可用記憶體時,将出現OutOfMemoryError。此類錯誤發生時,JVM将終止線程。
這些錯誤是不可查的,非代碼性錯誤。是以,當此類錯誤發生時,應用不應該去處理此類錯誤。
4.2、Exception(異常):程式本身可以捕獲并且可以處理的異常。這類異常需要我們程式員去捕獲異常、并處理異常、所謂真正的異常。
	異常有分為兩大類:
	RuntimeException(運作期間異常)
		我們在編寫好代碼之後、是的程式進行運作狀态的時候、發生了位置的異常資訊、比如、NullPointerException(空指針)、
		ArithmeticException(運算異常)等、像這樣的位置異常就屬于我們運作期間業務出錯手動造成的異常
	CheckedException(編譯期間異常)
		編譯期異常不難了解、我們都知道我們的java程式最終都是将.java檔案編譯成.class檔案、最後将class檔案運作在JVM虛
		拟機上的、那麼出現編譯期異常也就說明程式還沒有啟動在編譯過程中就已經出現錯誤了、絕大多數的錯誤就是類沒有調對、
		方法沒有寫正确、單詞寫錯、加載JAR包出現問題、代碼書寫不規範等原因造成的、仔細檢查排查出錯誤再繼續運作即可
           

5. 舉例說明

吃透JAVA中異常處理機制
吃透JAVA中異常處理機制

我們可以看出來、在上述程式中、并不屬于JVM或者系統内部的錯誤、而是我們的業務邏輯出現的錯誤、這樣的一場我們需要進行捕獲和處理、不然程式将無法正确執行。那麼我們程式員處理這類異常主要的方式有抛出異常和捕獲處理異常的兩種方式

使用try-catch-finally代碼塊來進行手動捕獲異常、并進行處理異常

吃透JAVA中異常處理機制
吃透JAVA中異常處理機制
5.1可檢查異常、和不受檢查異常

1、可查異常:編譯器要求必須處理的異常。正确的程式在運作過程中,經常容易出現的、符合預期的異常情況。一旦發生此類異常,就必須采用某種方式進行處理。除RuntimeException及其子類外,其他的Exception異常都屬于可查異常。編譯器會檢查此類異常,也就是說當編譯器檢查到應用中的某處可能會此類異常時,将會提示你處理本異常——要麼使用try-catch捕獲,要麼使用throws語句抛出,否則編譯不通過。

2、不可查異常:編譯器不會進行檢查并且不要求必須處理的異常,也就說當程式中出現此類異常時,即使我們沒有try-catch捕獲它,也沒有使用throws抛出該異常,編譯也會正常通過。該類異常包括運作時異常(RuntimeException極其子類)和錯誤(Error)。

5.2 異常處理的流程

在JAVA應用當中、異常處理的機制包括:捕獲異常和抛出異常兩種

抛出異常:當一個方法出現錯誤而引發異常的時候、該方法會将可能出現的異常資訊類型和異常出現的資訊封裝成一個異常對 象、任何代碼都可以通過throw關鍵詞抛出異常,比如java源代碼抛出異常、自己編寫的代碼抛出異常等。

捕獲異常:一旦方法抛出異常、系統會根據該異常對象去尋找對應的異常處理器(ExceptionHandler)、來處理異常。

6. try-catch-finally代碼塊的執行順序

吃透JAVA中異常處理機制

6.1 try-catch-finally代碼塊執行的順序

吃透JAVA中異常處理機制

從上述代碼中我們來進行分析try-catch-finally代碼塊的執行順序、假設現在1号程式代碼塊出現了異常資訊、那麼程式會進行将1号程式出現的異常資訊封裝成一個異常對象 e、并将e對象存放在本程式中、JVM會調用該異常對象所比對的ExceptionHandler異常處理器、最後傳回結果、可以看出、在1号程式出現錯誤的時候、2 号程式和3号程式都不會再去執行、直接進入異常處理的部分、在最後的finally代碼快中、無論程式是否發生異常資訊、都回去執行、那麼在封裝完異常對象之後、就隻執行finally代碼塊中的程式、一般在這塊代碼區域編寫一些釋放資源、檢查等後期維護等代碼塊

7. 總結異常

我們可以出現嵌套異常try-catch

吃透JAVA中異常處理機制

try代碼塊:用于捕獲異常。其後可以接零個或者多個catch塊。如果沒有catch塊,後必須跟finally塊,來完成資源釋放等操作,另外建議不要在finally中使用return,不用嘗試通過catch來控制代碼流程。

Throwa異常的基類、超級父類

Error是系統異常不需要處理

Exception是異常積累、需要進行程式員處理

8. 抛出異常資訊

public class Math {
    public int  method(int i,int j)throws Exception{
     int c =i/j;
     return c;      
    }
}
           

上述代碼我們可以看出、method方法抛出了一個異常資訊、那麼我們在調用這個方法的時候就需要進行對該方法抛出的異常資訊進行處理、不處理也可以那麼就是用throws向上繼續抛出該異常資訊即可、也可以使用try-catch語句進行内部處理、不在抛出抛異常、否則會報出編譯期異常資訊

吃透JAVA中異常處理機制

再來看這行代碼:我們使用throw自定義了一個異常資訊、當程式執行到16行的時候、出現了異常資訊、那麼17行就不會再去執行、并且報出編譯期間的異常、就說明在發生異常的情況下之後的代碼程式不再回去執行了

面試題 throws和throw的差別?

throws

  1. 用來定義一個方法可能出現的異常、一直往上抛、誰調用誰就來處理
  2. 用在方法聲明後面,跟的是異常類名
  3. 可以跟多個異常類名,用逗号隔開(可以同時抛出很多異常、也可以直接采用超類Exception)
  4. 表示抛出異常,由該方法的調用者來處理
  5. throws表示出現異常的一種可能性,并不一定會發生這些異常

throw

  1. 用來自定義一個異常資訊
  2. 一定會發生的一個異常資訊
  3. 主要聲明方式在方法體内進行聲明
  4. 每次隻能抛出一個異常對象
  5. 若執行了帶有throw的語句、那麼一定會抛出一個異常

9. 常見的異常類說明

java.lang.IllegalAccessError:違法通路錯誤。當一個應用試圖通路、修改某個類的域(Field)或者調用其方法,但是又違反域或方法的可見性聲明,則抛出該異常。

java.lang.InstantiationError:執行個體化錯誤。當一個應用試圖通過Java的new操作符構造一個抽象類或者接口時抛出該異常.

java.lang.OutOfMemoryError:記憶體不足錯誤。當可用記憶體不足以讓Java虛拟機配置設定給一個對象時抛出該錯誤。
java.lang.StackOverflowError:堆棧溢出錯誤。當一個應用遞歸調用的層次太深而導緻堆棧溢出或者陷入死循環時抛出該錯誤。

java.lang.ClassCastException:類造型異常。假設有類A和B(A不是B的父類或子類),O是A的執行個體,那麼當強制将O構造為類B的執行個體時抛出該異常。該異常經常被稱為強制類型轉換異常。
java.lang.ClassNotFoundException:找不到類異常。當應用試圖根據字元串形式的類名構造類,而在周遊CLASSPAH之後找不到對應名稱的class檔案時,抛出該異常。

java.lang.ArithmeticException:算術條件異常。譬如:整數除零等。
java.lang.ArrayIndexOutOfBoundsException:數組索引越界異常。當對數組的索引值為負數或大于等于數組大小時抛出。

java.lang.IndexOutOfBoundsException:索引越界異常。當通路某個序列的索引值小于0或大于等于序列大小時,抛出該異常。
java.lang.InstantiationException:執行個體化異常。當試圖通過newInstance()方法建立某個類的執行個體,而該類是一個抽象類或接口時,抛出該異常。

java.lang.NoSuchFieldException:屬性不存在異常。當通路某個類的不存在的屬性時抛出該異常。
java.lang.NoSuchMethodException:方法不存在異常。當通路某個類的不存在的方法時抛出該異常。
java.lang.NullPointerException:空指針異常。當應用試圖在要求使用對象的地方使用了null時,抛出該異常。譬如:調用null對象的執行個體方法、通路null對象的屬性、計算null對象的長度、使用throw語句抛出null等等。
java.lang.NumberFormatException:數字格式異常。當試圖将一個String轉換為指定的數字類型,而該字元串确不滿足數字類型要求的格式時,抛出該異常。

java.lang.StringIndexOutOfBoundsException:字元串索引越界異常。當使用索引值通路某個字元串中的字元,而該索引值小于0或大于等于序列大小時,抛出該異常。
           

10、其他異常

java.lang.AbstractMethodError:抽象方法錯誤。當應用試圖調用抽象方法時抛出。
java.lang.AssertionError:斷言錯。用來訓示一個斷言失敗的情況。
java.lang.ClassCircularityError:類循環依賴錯誤。在初始化一個類時,若檢測到類之間循環依賴則抛出該異常。
java.lang.ClassFormatError:類格式錯誤。當Java虛拟機試圖從一個檔案中讀取Java類,而檢測到該檔案的内容不符合類的有效格式時抛出。
java.lang.Error:錯誤。是所有錯誤的基類,用于辨別嚴重的程式運作問題。這些問題通常描述一些不應被應用程式捕獲的反常情況。
java.lang.ExceptionInInitializerError:初始化程式錯誤。當執行一個類的靜态初始化程式的過程中,發生了異常時抛出。靜态初始化程式是指直接包含于類中的static語句段。
java.lang.IncompatibleClassChangeError:不相容的類變化錯誤。當正在執行的方法所依賴的類定義發生了不相容的改變時,抛出該異常。一般在修改了應用中的某些類的聲明定義而沒有對整個應用重新編譯而直接運作的情況下,容易引發該錯誤。
java.lang.InternalError:内部錯誤。用于訓示Java虛拟機發生了内部錯誤。
java.lang.LinkageError:連結錯誤。該錯誤及其所有子類訓示某個類依賴于另外一些類,在該類編譯之後,被依賴的類改變了其類定義而沒有重新編譯所有的類,進而引發錯誤的情況。
java.lang.NoClassDefFoundError:未找到類定義錯誤。當Java虛拟機或者類裝載器試圖執行個體化某個類,而找不到該類的定義時抛出該錯誤。
java.lang.NoSuchFieldError:域不存在錯誤。當應用試圖通路或者修改某類的某個域,而該類的定義中沒有該域的定義時抛出該錯誤。
java.lang.NoSuchMethodError:方法不存在錯誤。當應用試圖調用某類的某個方法,而該類的定義中沒有該方法的定義時抛出該錯誤。
java.lang.ThreadDeath:線程結束。當調用Thread類的stop方法時抛出該錯誤,用于訓示線程結束。
java.lang.UnknownError:未知錯誤。用于訓示Java虛拟機發生了未知嚴重錯誤的情況。
java.lang.UnsatisfiedLinkError:未滿足的連結錯誤。當Java虛拟機未找到某個類的聲明為native方法的本機語言定義時抛出。
java.lang.UnsupportedClassVersionError:不支援的類版本錯誤。當Java虛拟機試圖從讀取某個類檔案,但是發現該檔案的主、次版本号不被目前Java虛拟機支援的時候,抛出該錯誤。
java.lang.VerifyError:驗證錯誤。當驗證器檢測到某個類檔案中存在内部不相容或者安全問題時抛出該錯誤。
java.lang.VirtualMachineError:虛拟機錯誤。用于訓示虛拟機被破壞或者繼續執行操作所需的資源不足的情況。
java.lang.ArrayStoreException:數組存儲異常。當向數組中存放非數組聲明類型對象時抛出。
java.lang.CloneNotSupportedException:不支援克隆異常。當沒有實作Cloneable接口或者不支援克隆方法時,調用其clone()方法則抛出該異常。
java.lang.EnumConstantNotPresentException:枚舉常量不存在異常。當應用試圖通過名稱和枚舉類型通路一個枚舉對象,但該枚舉對象并不包含常量時,抛出該異常。
java.lang.Exception:根異常。用以描述應用程式希望捕獲的情況。
java.lang.IllegalAccessException:違法的通路異常。當應用試圖通過反射方式建立某個類的執行個體、通路該類屬性、調用該類方法,而當時又無法通路類的、屬性的、方法的或構造方法的定義時抛出該異常。
java.lang.IllegalMonitorStateException:違法的監控狀态異常。當某個線程試圖等待一個自己并不擁有的對象(O)的監控器或者通知其他線程等待該對象(O)的監控器時,抛出該異常。
java.lang.IllegalStateException:違法的狀态異常。當在Java環境和應用尚未處于某個方法的合法調用狀态,而調用了該方法時,抛出該異常。
java.lang.IllegalThreadStateException:違法的線程狀态異常。當縣城尚未處于某個方法的合法調用狀态,而調用了該方法時,抛出異常。
java.lang.InterruptedException:被中止異常。當某個線程處于長時間的等待、休眠或其他暫停狀态,而此時其他的線程通過Thread的interrupt方法終止該線程時抛出該異常。
java.lang.NegativeArraySizeException:數組大小為負值異常。當使用負數大小值建立數組時抛出該異常。
java.lang.SecurityException:安全異常。由安全管理器抛出,用于訓示違反安全情況的異常。
java.lang.TypeNotPresentException:類型不存在異常。
           

繼續閱讀