Java入門系列-20-異常
為什麼要進行異常處理
下面這段程式碼能否正常執行
public class DemoCalc { public static void main(String[] args) { int a=0; int b=0; int c=a/b; System.out.println("運算結果為:"+c); } }
結果是我們在控制檯中看到一段錯誤提示,那是因為除數不能為0。異常就是在程式執行過程中發生的不正常事件,會中斷執行的程式 。
Java 使用了異常處理機制為程式提供了錯誤處理的能力,在程式中預先設定好對付異常的處理辦法,待程式發生異常時對異常進行處理,處理完畢後,程式便可以繼續執行。
下面來看一下Java中是如何進行異常處理的
如何進行異常處理
Java 的異常處理是通過5個關鍵字實現的:try、catch、finally、throw、throws
關鍵字 | 作用 |
---|---|
try | 執行可能產生異常的程式碼 |
catch | 捕獲異常 |
finally | 無論是否發生異常,程式碼總能執行 |
throws | 宣告方法要丟擲的異常 |
throw | 手動丟擲異常 |
常見異常及異常分類
Throwable 是Java 中所有錯誤和異常的父類
Error類:Throwable的子類,僅靠程式本身無法恢復的嚴重的錯誤。
Exception類:Throwable的子類,由Java應用程式丟擲和處理的非嚴重錯誤
RuntimeException類:Exception的子類,執行時異常,不要求程式必須做出處理。
Checked異常:Exception的子類,程式必須處理該類異常。
常見異常型別
異常型別 | 說明 |
---|---|
Exception | 異常層次結構的父類 |
ArithmeticException | 算數錯誤情形,如以零作除數 |
ArrayIndexOutOfBoundsException | 陣列下標越界 |
NullPointerException | 嘗試訪問null物件成員 |
ClassNotFoundException | 不能載入所需的類 |
IllegalArgumentException | 方法接收到非法引數 |
ClassCastException | 物件強制型別轉換出錯 |
NumberFormatException | 數字格式轉換異常,如把"abc"轉換成數字 |
try-catch
語法:
public void method(){ try{ //程式碼段1 //可能產生異常的程式碼段 //程式碼段2 }catch(異常型別 ex){ //對異常進行處理的程式碼段 } //程式碼段 }
try-catch塊捕獲異常有三種情況:
1、try塊中沒有任何異常,try中正常,catch不會執行,正常執行try-catch後的程式碼。
2、try塊中可能發生異常的程式碼段發生異常,程式碼段2不會執行,而是執行catch中異常處理的程式碼,正常執行try-catch後的程式碼。
catch中異常型別的printStackTrace() 方法能進行堆疊跟蹤顯示出程式執行到當前類的執行流程,異常堆疊資訊中包含了異常的型別及異常出現的位置。
3、異常型別不匹配,程式將中斷。比如try產生的異常為ArithmeticException,catch卻用了 ClassCastException。
在控制檯中接收數字做除法運算
import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("請輸入被除數(整數):"); int a=input.nextInt(); System.out.println("請輸入除數(整數):"); int b=input.nextInt(); int c=a/b; System.out.println("結果:"+c); }catch(Exception ex) { ex.printStackTrace(); } System.out.println("程式結束"); } }
try-catch-finally
語法:
public void method(){ try{ //可能會發生異常的程式碼 }catch(異常型別 ex){ //異常處理 }finally{ //無論如何都要執行的程式碼 } }
finally塊:是否發生異常都執行
finllay塊不執行的唯一情況:之前的程式碼中執行了 System.exit(1); 退出虛擬機器
try-catch-finally的使用
import java.io.FileNotFoundException; import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("請輸入被除數(整數):"); int a=input.nextInt(); System.out.println("請輸入除數(整數):"); int b=input.nextInt(); int c=a/b; System.out.println("結果:"+c); }catch(Exception ex) { ex.printStackTrace(); }finally { System.out.println("感謝您的使用"); } System.out.println("程式結束"); } }
如果在try塊或catch塊中有return語句,finally是否還會執行?執行下面程式碼斷點除錯觀察結果。
public class TestReturn { public static void main(String[] args) { try { int a=1+1; System.out.println("try執行"); return; } catch (Exception e) { System.out.println("catch執行"); }finally { System.out.println("finally執行"); } } }
try塊或catch塊中可以有return語句,如果有return語句會先執行finally最後再執行return。
多重catch
try塊中可能會發生多種異常,如果要不同的異常進行不同的處理,需要使用多重catch進行處理。
語法:
public void method(){ try{ //可能發生異常的程式碼段 }catch(異常型別1 e){ //對異常型別1進行的處理的程式碼段 }catch(異常型別2 e){ //對異常型別2進行的處理的程式碼段 }catch(異常型別n e){ //對異常型別n進行的處理的程式碼段 } }
當try塊中發生異常後,會逐個與catch中的異常型別進行匹配,匹配成功後,進入對應的catch進行異常處理,處理完成後不再進入其他catch,程式繼續執行。
排列catch語句的順序是:先子類後父類
發生異常時按順序逐個匹配
只執行第一個與異常型別匹配的catch語句
將之前的程式碼 DemoInput.java 改造成多重catch
import java.io.FileNotFoundException; import java.util.InputMismatchException; import java.util.Scanner; public class DemoInput { public static void main(String[] args) { Scanner input=new Scanner(System.in); try{ System.out.println("請輸入被除數(整數):"); int a=input.nextInt(); System.out.println("請輸入除數(整數):"); int b=input.nextInt(); int c=a/b; System.out.println("結果:"+c); }catch(InputMismatchException e) { System.out.println("輸入的數有誤!"); }catch(ArithmeticException e) { System.out.println("除數不能為0"); }catch(Exception ex) { System.out.println("發生未知異常"); }finally { System.out.println("感謝您的使用"); } System.out.println("程式結束"); } }
宣告異常 throws
如果一個方法體內丟擲了異常如何通知呼叫者,可以在方法上宣告異常。
public class TestThrows { //宣告異常,多個異常可以用逗號隔開 public void test()throws Exception,ClassNotFoundException{ //可能會發生異常的程式碼 } }
處理方式一:呼叫者處理異常
public static void main(String[] args) { TestThrows t=new TestThrows(); try { t.test(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
處理方式二:呼叫者繼續宣告異常
public static void main(String[] args) throws ClassNotFoundException, Exception { TestThrows t=new TestThrows(); t.test(); }
main方法繼續宣告異常,呼叫者就變成虛擬機器了,發生異常則按預設方式處理,打印出來。
丟擲異常 throw
除了系統自動丟擲的異常外,有些問題需要程式設計師自行丟擲異常
public class TestThrow { public void inputAge(int age) throws Exception { if (age<1) { throw new Exception("還有這種年齡?"); } } public static void main(String[] args) { TestThrow t=new TestThrow(); try { t.inputAge(-1); } catch (Exception e) { System.out.println("年齡有誤:"+e.getMessage()); } } }
自行丟擲異常後,還需要在方法上宣告異常