第四階段 IO
異常處理
沒有完美的程序,所以我們需要不斷地完善,考慮各種可能性,我們要將除了自己以外的任何用戶或者操作者都當成傻子來考慮問題
在我們開發過程中 我們運行時常常會遇到 這樣java.lang.XxxException的信息,這代表程序發生了一些錯誤,也叫作異常
(一) 概述及體系
(1) 概述
異常情形是指阻止當前方法或者作用域繼續執行的問題 ——《Think in Java》
簡單概括:程序出現不正常情況后,程序將會跳出當前環境,並且拋出異常。
(2) 體系
(1) Error —— 錯誤:程序無法處理的嚴重錯誤,我們不作處理
- 這種錯誤一般來說與操作者無關,並且開發者與應用程序沒有能力去解決這一問題,通常情況下,JVM會做出終止線程的動作
(2) Exception —— 異常:異常可以分為運行時異常和編譯期異常
-
RuntimeException:即運行時異常,我們必須修正代碼
-
這些異常通常是由於一些邏輯錯誤產生的
這類異常在代碼編寫的時候不會被編譯器所檢測出來,是可以不需要被捕獲,但是程序員 也可以根據需要行捕獲拋出,(不受檢查異常)這類異常通常是可以被程序員避免的。
常見的RUNtimeException有:NullpointException(空指針異常),ClassCastException (類型轉 換異常),IndexOutOfBoundsException(數組越界異常)等。
-
-
非RuntimeException:編譯期異常,必須處理,否則程序編譯無法通過
- 這類異常在編譯時編譯器會提示需要捕獲,如果不進行捕獲則編譯錯誤。
- 常見編譯異常有:IOException(流傳輸異常),SQLException(數據庫操作異常)等。
Java內置異常類
A:Java 的非檢查性異常
異常 | 描述 |
---|---|
ArithmeticException | 當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。 |
ClassCastException | 拋出表示代碼嘗試將對象轉換為不屬於實例的子類。 例如:將Integer型對象轉換為String類 |
IllegalArgumentException | 拋出的異常表明向方法傳遞了一個不合法或不正確的參數。 |
NumberFormatException | 拋出以表示應用程序已嘗試將字符串轉換為其中一個數字類型,但該字符串不具有相應的格式。 |
IllegalStateException | 表示在非法或不適當的時間調用了一種方法。 換句話說,Java環境或Java應用程序對於請求的操作並不處於適當的狀態。 |
IndexOutOfBoundsException | 指示某排序索引(例如對數組、字符串或向量的排序)超出范圍時拋出。 應用程序可以將此類子類化以指示類似的異常。 |
ArrayIndexOutOfBoundsException | 用非法索引訪問數組時拋出的異常。如果索引為負或大於等於數組大小,則該索引為非法索引。 |
NoSuchElementException | 被各種訪問器方法拋出,表示被請求的元素不存在。 |
InputMismatchException | 輸入類型不匹配異常,一般出現此類異常的原因就是定義的接受輸入值的變量的類型與輸入的數值的類型不匹配導致的異常。 |
NullPointerException | 空指針異常 |
B:Java的檢查性異常
異常 | 描述 |
---|---|
ClassNotFoundException | 應用程序試圖加載類時,找不到相應的類,拋出該異常。 |
CloneNotSupportedException | 當調用 Object 類中的 clone 方法克隆對象,但該對象的類無法實現 Cloneable 接口時,拋出該異常。 |
InstantiationException | 當試圖使用 Class 類中的 newInstance 方法創建一個類的實例,而指定的類對象因為是一個接口或是一個抽象類而無法實例化時,拋出該異常。 |
(二) 異常處理語句
(1) try-catch
A:捕獲單個異常
try{
//程序代碼
}catch (ExceptionName e1){
//Catch塊
}
B:多重捕獲塊
try{
//程序代碼
}catch (異常類型1 異常的變量名1){
......
}catch (異常類型2 異常的變量名2){
......
}catch (異常類型3 異常的變量名3){
......
}
try:用於監聽異常
catch:用於捕獲處理異常
try 后面的一對大括號內的內容即受到監控的程序,也就是說這一段代碼是可能存在異常的,而Catch中由開發者,根據自身推斷可能存在的異常,書寫對應異常類型以及處理方式,當程序發生異常時,會創建異常對象,並且將異常拋出到此環境外,Java運行時系統會尋找與發生異常所匹配的catch子句,當找到一個對應語句后則不再尋找其他catch塊
public class Demo {
public static void main(String[] args) {
int a = 520;
int b = 0;
int c;
try {
System.out.println("這是一個被除數為0的式子");
c = a / b;
} catch (ArithmeticException e) {
System.out.println("除數不能為0");
}
}
}
//運行結果
這是一個被除數為0的式子
除數不能為0
通過上例可以看到,被監控的語句中先依次正常執行,當遇到存在問題的語句時,找到匹配異常,並且執行catch塊中的語句
而一般來說我們會在catch語句塊中通過異常對象執行異常方法
方法方法 | 說明 |
---|---|
public String getMessage() | 回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了 |
public Throwable getCause() | 返回一個Throwable 對象代表異常原因 |
public String toString() | 使用getMessage()的結果返回類的串級名字 |
public void printStackTrace() | 打印toString()結果和棧層次到System.err,即錯誤輸出流 |
我們還是用上面的例子給出異常方法的測試
System.out.println(e.getMessage());
/ by zero
System.out.println(e.getCause());
null
System.out.println(e.toString());
java.lang.ArithmeticException: / by zero
e.printStackTrace();
java.lang.ArithmeticException: / by zero
at cn.bwh_01_Throwable.Demo.main(Demo.java:10)
(2) try-catch-finally
我們在 try-catch的基礎上再補充一個finally的知識
finally 關鍵字用來創建在 try 代碼塊后面執行的代碼塊無論是否發生異常,finally 代碼塊中的代碼總會被執行,在 finally 代碼塊中,可以運行清理類型等收尾善后性質的語句,finally 代碼塊出現在 catch 代碼塊最后,語法如下:
try{
......
}catch(異常類型1 異常的變量名1){
......
}catch(異常類型2 異常的變量名2){
......
}finally{
......
}
無論是否發生異常,fianlly始終都是會運行的
這里就不得不提一個非常重要的注意點,那就是當return遇到finally!
注意點
A:return遇到finally
我們來看下面一個例程:
public class Demo2 {
public static void main(String[] args) {
System.out.println(test());
}
public static String test(){
int[] array = new int[2];
try{
array[3] = 0;
return "This is try";
}catch (ArrayIndexOutOfBoundsException e){
System.out.println(e);
return "This is catch 1";
}catch (Exception e){
System.out.println(e);
return "This is catch 2";
}finally {
System.out.println("This is finally");
//return "This is finally's return";
}
}
}
//運行結果
java.lang.ArrayIndexOutOfBoundsException: 3
This is finally
This is catch 1
由此我們得出一個結論:在catch中遇到return時,仍然會先執行finally語句,再回來執行對應catch語句中的return語句
但是我們如果將finally中return行中的注釋去掉,運行結果就會變成下面這樣子
//運行結果
java.lang.ArrayIndexOutOfBoundsException: 3
This is finally
This is finally's return
結果就是返回值會被finally中的return語句重新覆蓋
B:catch 順序問題
public class Demo3 {
public static void main(String[] args) {
int[] array = new int[2];
try{
array[5] = 0;
}catch (Exception e){
}catch (ArrayIndexOutOfBoundsException e){
}
}
}
//運行結果
Error:(8, 10) java: 已捕獲到異常錯誤java.lang.ArrayIndexOutOfBoundsException
對於多個catch的情況,當try中程序發生異常,會按照從上往下的順序與catch進行匹配,一旦與其中一個匹配后就不會再與后面的catch進行匹配了,所以,在書寫catch語句的時候,一定要把范圍小的放在前面,范圍大的放在后面!
(3) throw/throws
將自己處理不了的,在方法或者語句上聲明,告訴調用者,這里有問題
如果一個方法沒有捕獲到檢查性異常,那么該方法就必須使用throws關鍵字聲明(聲明拋出多個異常,之間使用逗號隔開),也可以在語句中使用throw關鍵字拋出一個異常。
//演示throw
public class Demo4 {
public static void main(String[] args) {
test();
}
public static void test() {
int a = 520;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
}
//運行結果
Exception in thread "main" java.lang.ArithmeticException
//演示throws
public class Demo4 {
public static void main(String[] args) {
try {
test();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void test() throws Exception {
int a = 520;
int b = 0;
if (b == 0) {
throw new Exception();
} else {
System.out.println(a / b);
}
}
}
//運行結果
java.lang.Exception
throws和throw的區別
A:throws
- 用在方法聲明后,跟的是異常類名
- 可以跟多個異常類名,用逗號隔開
- 表示拋出異常,由該方法的調用者來處理
- throws表示出現異常的一種可能性,不一定會發生這些異常
B:throw
-
用在方法體內,跟的是異常對象名
-
只能拋出一個異常對象名
-
表示拋出異常,由方法體內的語句處理
-
執行throw則一定拋出了某種異常
(三) 自定義異常
Java內置的異常類,基本可以滿足我們在編程中遇到的大部分異常情況,此外我們還可以自定義異常類,只需要繼承Exception類即可
基本步驟:
-
創建自定義異常類
-
在方法中通過throw拋出異常對象
- 在當前拋出異常的方法中處理異常,可以使用try-catch語句捕獲處理
- 也可以在方法聲明處使用throws將異常拋給方法調用者
-
在出現異常方法的調用者中捕獲並且處理異常
class MyException extends Exception { // 自定義的類
MyException(String s) {
super(s);
}
}
class Demo {
void method() throws MyException {
throw new MyException("Wrong"); // 拋出自定義的類
}
}
class DemoTest {
public static void main(String[] args){
try {
new Demo().method();
}
catch(MyException e) {
System.out.println(e.getMessage());
}
}
}
//運行結果
Wrong
(三) 總結
異常就是在程序發生異常時,強制終止程序運行,並且將異常信息返回,由開發者決定是否處理異常
簡單說一下這個異常機制的過程:
當程序無法運行后,它會從當前環境中跳出,並且拋出異常,之后,它會先new一個異常對象,然后在異常位置終止程序,並且將異常對象的引用從當前環境中返回,這時候異常處理機制接管程序,並且開始尋找可以繼續執行程序的恰當位置。
結尾:
如果內容中有什么不足,或者錯誤的地方,歡迎大家給我留言提出意見, 蟹蟹大家 !_
如果能幫到你的話,那就來關注我吧!(系列文章均會在公眾號第一時間更新)
在這里的我們素不相識,卻都在為了自己的夢而努力 ❤
一個堅持推送原創Java技術的公眾號:理想二旬不止