爲什麼要用異常?
原因是在你編寫代碼的時候編譯器會檢測出大多數的異常,而一少部分會餘留到運行期間解決。當編寫大型的程序時,異常可以降低錯誤處理代碼的複雜度。如果不使用異常,那麼就必須檢查特定的錯誤,並在程序中的許多地方處理它,從而降低了代碼的維護性。如果使用異常,那就不必在方法調用出進行檢查,因爲異常機制將保證能夠捕獲這個錯誤,並且是只有在一個地方即可。
異常的分類
java的異常機制是建立在C++的基礎之上。
Thorwable類所有異常和錯誤的超類,有兩個子類Error和Exception,分別表示錯誤和異常。其中異常類Exception又分爲運行時異常(RuntimeException)和非運行時異常,這兩種異常有很大的區別,也稱之爲不檢查異常(Unchecked Exception) 和 檢查異常(Checked Exception)。
運行時異常 —> UncheckedException 程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度儘可能避免這類異常的發生。編譯是可以通過的。
非運行時異常—>CheckedException 類型上都屬於Exception類及其子類。從程序語法角度講是必須進行處理的異常,如果不處理,程序就不能編譯通過。如IOException、SQLException等以及用戶自定義的Exception異常,一般情況下不自定義檢查異常。
Error 和 Exception
Error是程序無法處理的錯誤,比如OutOfMemoryError、ThreadDeath等。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止,程序將會終止。
Exception是程序本身可以處理的異常,這種異常分兩大類,運行時異常和非運行時異常。程序中應當儘可能去處理這些異常。
常見的異常
異常類 | 意義 |
---|---|
ClassCastException | 類型轉換異常 |
NullPointerException | 空指針異常 |
IndexOutOfBoundsException | 數組下標異常 |
ArithmeticException | 算術異常 |
NumberFormatException | 字符串轉換爲數字異常 |
IllegalArgumentException | 非法參數異常 |
SecurityException | 安全性異常 |
public class Demo {
public static void main(String[] args) {
int[] arr= new int[5];
System.out.println(arr[5]);
}
}
Throwable異常方法
方法 | 介紹 |
---|---|
getMessage() | 獲取有關異常事件信息 |
toString() | 獲取異常的類型與性質 |
printStackTrace() | 獲取異常發生時執行堆棧的內容 |
getCause() | 返回一個Throwable 對象代表異常原因 |
getStackTrace() | 返回一個包含堆棧層次的數組。下標爲0的元素代表棧頂,最後一個元素代表方法調用堆棧的棧底 |
fillInStackTrace() | 用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中 |
捕獲處理異常
異常處理有兩種解決的方案:一種try……catch(捕獲並處理異常)語句,另外一種throw(拋出異常)。
try……catch語句
try {
}catch (Exception e){
}finally {
}
try:一般都在try裏面編寫可能發生異常的代碼塊。
catch: 在try代碼塊發生異常時,只有進入catch語句塊,異常纔可以被處理,catch語句塊可以有n個(並且子類必須在父類之前,否則就會發生錯誤)。
finally這個代碼塊是異常發生不發生都會執行的代碼塊,都是最後執行。一般情況下該部分都是釋放資源或者關閉對象。finally不執行的情況:在finally裏面發生異常。
public class Demo {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5};
try{
System.out.println("第五個元素"+arr[5]);
}catch (Exception e){//這塊也可以將Exception改爲ArrayIndexOutOfException
System.out.println("下標不能大於4,數組下標異常");
}
}
}
從圖中可以看出程序並沒有因此中斷而是對其異常進行了處理最後執行完成。
從上圖中可以看出兩個catch語句的順序不一樣導致了編譯器出現了錯誤提示。Exception是所有的子異常的父類,如果將Exception放在子類之前那麼後面的語句就不會執行,也就沒有什麼意義了。
throws關鍵詞
throws關鍵詞是在聲明方法時候用來指定方法可能拋出的異常。
public class asdsad{
//主線程
public synchronized void main() throws Exception {
}
//子線程
public synchronized void child() throws Exception {//這種就是throws在方法總拋出異常
}
public static void main(String[] args) throws Exception {
asdsad asdsad = new asdsad();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println();
try {
asdsad.child();
} catch (Exception e) {
e.printStackTrace();
}
}
}
},"子線程").start();
for (int i = 0; i < 10; i++) {
System.out.println();
asdsad.main();//這塊也可以加try……catch語句 main() 後面就可以不需要了
}
}
}
如果方法拋出了異常(child、main),那麼在調用的時候就要使用try……catch語句捕獲並處理異常或者向上繼續拋出異常就像如上代碼調用main方法 把異常拋給了Exception處理。
這裏需要注意:使用throws爲方法拋出異常,如果子類繼承父類,子類重寫的方法和原父類方法拋出的異常相同、或者是其異常的子類,除非throws異常時RuntimeException。
throw關鍵詞
throw關鍵詞通常用於在方法體之中“製造一個異常”,程序在執行到throw語句時立即終止,它後面的語句都不會得到執行。
public class Demo {
public static void main(String[] args) {
int num_1 = 10;
int num_2 = 0;
if(num_2 == 0){
throw new ArithmeticException("除數不爲0");
}
int res = num_1/num_2;
System.out.println(res);
}
}
throw通常用來拋出用戶自定義異常,通過throw關鍵詞拋出異常後,如果想在上一級代碼中捕獲並處理異常,最好在拋出異常的方法聲明中使用throws關鍵詞指明要拋出的異常;如果要捕捉throw拋出的異常,則使用try……catch代碼塊。
throw與throws區別
- throws用在方法聲明後面,表示拋出異常,由方法的調用者處理,而throw用在方法體內,用來創造一個異常,由方法體內的語句處理。
- throws是聲明這個方法會拋出這種類型的異常,以便使他的調用者知道要捕獲這個異常,而throw是直接拋出一個異常實列。
- throws表示出現異常的一種可能性,並一定會發生這些異常,如果使用throw,就一定產生某種異常。
用戶自定義異常
爲什麼要自定義異常?
就是java內置異常無法識別的情況下才自定義異常、比如:年齡不能爲負數。
自定義異常使用場景:
程序中出現錯誤是符合java語法,編譯器檢測不出,也可以編譯,比如:人的年齡不能爲負數,人數不能爲小數等等。(這塊我總結的不全面)
int age = -10;
System.out.println("小明今年"+age);
如上就可以輸出,要避免這種情況我們就可以自定義一個異常類。
public class ageDemo {
public static void ages(int age) throws MyException{
if(age<0){
throw new MyException("年齡不可以使用負數");
}else{
System.out.println("小明今年"+age);
}
}
public static void main(String[] args) {
int age = -10;
try {
ages(age);
} catch (MyException e) {
e.printStackTrace();
}
}
}
這種情況下可以識別年齡不能爲負數。
異常使用的原則(書上內容)
java異常強制用戶去考慮程序的強健性和安全性。
應該遵循以下原則:
- 不要過度使用異常。雖然通過異常可以增強程序的健壯性,但是如果使用過多的異常處理,可能會影響程序的執行效率。
- 不要使用龐大的try……catch塊。在一個try塊防止大量的代碼,業務過於複雜,如果try塊出現異常,那麼分析找原因的難度將大大增大。
- 避免使用catch(Exception e)。因爲所有的異常都採用了同一種處理的方式,將導致不能對不同異常分情況處理。比如:ArrayIndexOutOfException和ClassCastException一起都在一個catch代碼塊處理。
- 不要忽略捕捉到的異常,遇到異常一定要及時的處理。
- 如果父類拋出多個異常,則覆蓋方法必須拋出相同的異常或異常子類,不能拋出新的異常。
不全的內容請大佬補充
看完感覺有用的點個贊,沒有的也點個贊
嘻嘻~