Java异常详解
一、Java異常概述?
在Java中,所有的事件都能由類描述,Java中的異常就是由java.lang包下的異常類描述的。
?
Throwable(可拋出):異常類的最終父類,它有兩個子類,Error與Exception。?
Throwable中常用方法有:?
getCause():返回拋出異常的原因。如果 cause 不存在或未知,則返回 null。?
getMeage():返回異常的消息信息。?
printStackTrace():對象的堆棧跟蹤輸出至錯誤輸出流,作為字段 System.err 的值。
?
1、Error(錯誤):表示程序無法處理的錯誤,一般與程序員的執行操作無關。理論上這些錯誤是不允許發生的,如果發生,也不應該試圖通過程序去處理,所以Error不是try-catch的處理對象,而JVM一般的處理方式是終止發生錯誤的線程。Error類常見子類有VirtualMachineError與AWTError。
1-1、VirtualMachineError(虛擬機錯誤):表示虛擬機出現錯誤。?在Java運行時內存中,除程序計數器外的虛擬機棧、堆、方法區在請求的內存無法被滿足時都會拋出OutOfMemoryError;?而如果線程請求的棧深度超出虛擬機允許的深度時,就會拋出StackOverFlowError。
1-2、AWTError(AWT組件出錯):這個錯誤并不是很常用。但是提一下AWT與Swing的區別,AWT是使用操作系統中的圖形函數的抽象窗口工具,用C\C++編寫,為了實現Java“一次編譯,處處運行”的理念,AWT使用各個操作系統圖形函數的交集,所以功能較差,但運行速度較快,適合嵌入式Java;?而Swing組件是基于AWT編寫的圖形界面系統,它用純Java編寫,所以必然實現了“一次編譯,處處運行”,但相較于AWT運行速度較慢,適合PC使用。
2、Exception(異常):出現原因取決于程序,所以程序也理應通過try-catch處理。?異常分為兩類:可查異常(checked)與不可查異常(unchecked)。
2-1、可查異常:編譯器要求必須處理,否則不能通過編譯,使用try-catch捕獲或者throws拋出。常見的可查異常有IOException(IO錯誤)及其子類EOFExcption(文件已結束異常)、FileNotFound(文件未找到異常)。
2-2、不可查異常(也叫運行時異常):編譯期不會檢查,所以在程序中可不處理,但如果發生,會在運行時拋出。所以這類異常要盡量避免!常見的不可查異常都是RuntimeException類及其子類。
2-2-1、NullPointerException:空指針異常。調用了不存在的對象或未經實例化或初始化的對象時會拋出,如當試圖操作一個空對象(賦值為null)的屬性、方法時就會拋出。
(實例化:通俗的理解就是為對象開辟空間,使其可在規定范圍內被調用。注意:User u;這只是一個對象聲明,并沒有進行實例化或初始化。?
初始化:就是把實例化后的對象中的基本數據類型字段賦默認值或設定值,為非基本類型賦值null,對于static字段只會初始化一次。)
2-2-2、ArithmeticException:算術條件異常。最常見的就是0作除數時會拋出。
2-2-3、ClassNotFoundException:類未找到異常。在通過反射Class.forName(“類名”)來獲取類時,如果未找到則會拋出異常。
2-2-4、ArrayIndexOutOfBoundsException:數組索引越界異常。當試圖操作數組的索引值為負數或大于等于數組大小時會拋出。
2-2-5、NegativeArraySizeException:數組長度為負值異常。一般在初始化數組大小為負值時拋出。
2-2-6、ArrayStoreException:數組類型不匹配值異常。例如將一個Object數組中加入一個Integer對象與一個String對象時,類型不匹配就會拋出。
2-2-7、IllegalArgumentException:非法參數異常。會在使用Java類庫方法時傳入參數值越界時拋出。
?
二、unchecked異常和checked異常的區別
Java的異常被分為兩大類:Checked異常和Unchecked異常(Runtime異常)。
所有RuntimeException類及其子類的實例被稱為Unchecked異常;
不是RuntimeException類及其子類的異常實例則被稱為Checked異常。
checked異常:
- 表示無效,不是程序中可以預測的。比如無效的用戶輸入,文件不存在,網絡或者數據庫鏈接錯誤。這些都是外在的原因,都不是程序內部可以控制的。
- 必須在代碼中顯式地處理。比如try-catch塊處理,或者給所在的方法加上throws說明,將異常拋到調用棧的上一層。
- 繼承自java.lang.Exception(java.lang.RuntimeException除外)。
unchecked異常:
- 表示錯誤,程序的邏輯錯誤。是RuntimeException的子類,比如IllegalArgumentException, NullPointerException和IllegalStateException。
- 不需要在代碼中顯式地捕獲unchecked異常做處理。
- 繼承自java.lang.RuntimeException(而java.lang.RuntimeException繼承自java.lang.Exception)。
Java認為Checked異常都是可以被處理(修復)的異常,所以Java程序必須顯示處理Checked異常。如果程序沒有處理Checked異常,該程序在編譯時就會發生錯誤,無法通過編譯。
對于Checked異常處理方式有如下兩種:
(1)當前方法明確知道如何處理該異常,程序應該使用try...catch塊來捕獲該異常,然后在對應的catch塊中修改該異常。
(2)當前方法不知道如何處理這種異常,應該在定義該方法時聲明拋出該異常。
Runtime異常無需顯式聲明拋出,如果程序需要捕捉Runtime異常,也可以使用try...catch塊來捕捉Runtime異常。
Java異常之所以會分為這兩種,應該是出于如下考慮:checked異常可以幫助開發人員意識到哪一行有可能會出現異常,因為Java的API已經說明了調用哪些方法可能會拋出異常。如果不做處理編譯就不能通過,從某種程度上說,這種做法可以避免程序的一些錯誤。
三、使用throws聲明拋出異常
1、throws聲明拋出異常的思路是:當前方法不知道應該如何這種類型的異常,該異常應該由上一級調用者處理,如果main方法也不知道應該如何處理這種類型的異常,也可以使用throws聲明拋出異常,該異常將交給JVM處理。JVM對異常的處理方法是:打印異常跟蹤棧信息,并中止程序運行,這就是前面程序在遇到異常后自動結束的原因。
2、throws聲明拋出只能在方法簽名中使用,throws可以聲明拋出多個異常類,多個異常類之間以逗號隔開。throws聲明拋出的語法格式如下:throws ExceptionClass1 , ExceptionClass2...
下面給出幾個關于throw的例子
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
例1
1、代碼示例
import java.io.*; public class ThrowsTest {public static void main(String[] args) throws IOException{FileInputStream fis = new FileInputStream("a.txt");} }2、 運行結果
Exception in thread "main" java.io.FileNotFoundException: a.txt (系統找不到指定的文件。)
?at java.io.FileInputStream.open(Native Method)
?at java.io.FileInputStream.<init>(FileInputStream.java:106)
?at java.io.FileInputStream.<init>(FileInputStream.java:66)
?at ThrowsTest.main(ThrowsTest.java:9)
3 、結果分析
該程序不處理IOException異常,將該異常交給JVM處理,所以程序一旦遇到異常,JVM就會打印該異常的跟蹤棧信息,并結束程序。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
例2
1、代碼示例
import java.io.*; public class ThrowsTest2 {public static void main(String[] args) throws Exception{// 因為test()方法聲明拋出IOException異常,所以調用該方法的代碼要么處于try...catch塊中,// 要么處于另一個帶throws聲明拋出的方法中。test();}public static void test()throws IOException{// 因為FileInputStream的構造器聲明拋出IOException異常,// 所以調用FileInputStream的代碼要么處于try...catch塊中,// 要么處于另一個帶throws聲明拋出的方法中。FileInputStream fis = new FileInputStream("a.txt");} }2、 運行結果
Exception in thread "main" java.io.FileNotFoundException: a.txt (系統找不到指定的文件。)
?at java.io.FileInputStream.open(Native Method)
?at java.io.FileInputStream.<init>(FileInputStream.java:106)
?at java.io.FileInputStream.<init>(FileInputStream.java:66)
?at ThrowsTest2.test(ThrowsTest2.java:19)
?at ThrowsTest2.main(ThrowsTest2.java:12)
3 、結果分析
test方法聲明拋出了Checked異常,則表明該方法希望它的調用者來處理該異常。main方法要么放在try塊中顯示捕獲該異常,要么帶throws聲明拋出讓JVM處理。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
例3
1 、代碼示例
import java.io.*; public class OverrideThrows {public void test()throws IOException{FileInputStream fis = new FileInputStream("a.txt");} } class Sub extends OverrideThrows {// 子類方法聲明拋出了比父類方法更大的異常,所以下面方法出錯public void test()throws Exception{} }2 、運行結果
編譯無法通過。
3 、結果分析
throws聲明拋出時有一個限制:子類方法聲明拋出的異常類型應該是父類方法聲明拋出的異常類型的子類或相同,子類方法聲明拋出的異常不允許比父類聲明拋出異常多。
上面程序中Sub子類中的test()方法聲明拋出Exception,該Exception是父類聲明拋出異常IOException類的父類,導致程序無法通過編譯
四、使用try-catch-finally捕捉異常
1、捕獲語句
try中是可能發生異常的程序段;
catch中依次編寫對應的異常處理器方法,當拋出異常后,由運行時系統在棧中從當前位置開始依次回查方法,直到找到合適的異常處理方法,如果未找到,則執行finally或直接結束程序運行。
finally?:無論是否捕獲或處理異常,finally塊里的語句都會被執行。?
注意(很重要,面試常問):當在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執行。?
在以下4種特殊情況下,finally塊不會被執行:?
1)在finally語句塊中拋出了異常且未處理。?
2)在前面的代碼中用了System.exit()退出程序。?
3)程序所在的線程死亡。?
4)CPU出現異常被關閉。
?2、執行順序
1)當沒有異常捕獲時,會跳過catch,直接執行finally塊。
2)當拋出運行時異常且沒有定義相應的異常處理方法,就會由JVM拋出異常。
3)當try捕獲到異常,catch語句塊里有處理此異常的情況:在try語句塊中是按照順序來執行的,當執行到某一條語句出現異常時,程序將跳到catch語句塊,并與catch語句塊逐一匹配,找到與之對應的處理程序,其他的catch語句塊將不會被執行,而try語句塊中,出現異常之后的語句也不會被執行,catch語句塊執行完后,最后執行finally語句塊后的語句。
?
轉載于:https://www.cnblogs.com/songshu120/p/7909793.html
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
- 上一篇: tomcat JRE_HOME
- 下一篇: BZOJ 3289 Mato的文件管理