異常是程序中的一些錯誤,但並不是所有的錯誤都是異常,並且錯誤有時候是可以避免的。
比如說,你的代碼少了一個分號,那麼運行出來結果是提示是錯誤java.lang.Error;如果你用System.out.println(11/0),那麼你是因為你用0做了除數,會拋出java.lang.ArithmeticException的異常。
異常發生的原因有很多,通常包含以下幾大類:
這些異常有的是因為用戶錯誤引起,有的是程序錯誤引起的,還有其它一些是因為物理錯誤引起的。-
要理解Java異常處理是如何工作的,你需要掌握以下三種類型的異常:
所有的異常類是從java.lang.Exception類繼承的子類。
Exception類是Throwable類的子類。除了Exception類外,Throwable還有一個子類Error 。
Java程序通常不捕獲錯誤。錯誤一般發生在嚴重故障時,它們在Java程序處理的范疇之外。
Error用來指示運行時環境發生的錯誤。
例如,JVM內存溢出。一般地,程序不會從錯誤中恢復。
異常類有兩個主要的子類:IOException類和RuntimeException類。
在Java 內置類中(接下來會說明),有大部分常用檢查性和非檢查性異常。
Java 語言定義了一些異常類在java.lang標准包中。
標准運行時異常類的子類是最常見的異常類。由於java.lang包是默認加載到所有的Java程序的,所以大部分從運行時異常類繼承而來的異常都可以直接使用。
Java根據各個類庫也定義了一些其他的異常,下面的表中列出了Java的非檢查性異常。
null
時,拋出該異常
NumberFormatException
當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換為適當格式時,拋出該異常。
SecurityException
由安全管理器拋出的異常,指示存在安全侵犯。
StringIndexOutOfBoundsException
此異常由 String
方法拋出,指示索引或者為負,或者超出字符串的大小。
UnsupportedOperationException
當不支持請求的操作時,拋出該異常。
下面的表中列出了Java定義在java.lang包中的檢查性異常類。
Object
類中的 clone
方法克隆對象,但該對象的類無法實現 Cloneable
接口時,拋出該異常。
IllegalAccessException
拒絕訪問一個類的時候,拋出該異常。
InstantiationException
當試圖使用 Class
類中的 newInstance
方法創建一個類的實例,而指定的類對象因為是一個接口或是一個抽象類而無法實例化時,拋出該異常。
InterruptedException
一個線程被另一個線程中斷,拋出該異常。
NoSuchFieldException
請求的變量不存在
NoSuchMethodException
請求的方法不存在
下面的列表是Throwable 類的主要方法:
使用try和catch關鍵字可以捕獲異常。try/catch代碼塊放在異常可能發生的地方。
try/catch代碼塊中的代碼稱為保護代碼,使用 try/catch的語法如下:
try { // 程序代碼 }catch(ExceptionName e1) { //Catch 塊 }
Catch語句包含要捕獲異常類型的聲明。當保護代碼塊中發生一個異常時,try後面的catch塊就會被檢查。
如果發生的異常包含在catch塊中,異常會被傳遞到該catch塊,這和傳遞一個參數到方法是一樣。
下面的例子中聲明有兩個元素的一個數組,當代碼試圖訪問數組的第三個元素的時候就會拋出一個異常。
// 文件名 : ExcepTest.java import java.io.*; public class ExcepTest{ public static void main(String args[]){ try{ int a[] = new int[2]; System.out.println("Access element three :" + a[3]); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("Exception thrown :" + e); } System.out.println("Out of the block"); } }
以上代碼編譯運行輸出結果如下:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 Out of the block
一個try代碼塊後面跟隨多個catch代碼塊的情況就叫多重捕獲。
多重捕獲塊的語法如下所示:
try{ // 程序代碼 }catch(異常類型1 異常的變量名1){ // 程序代碼 }catch(異常類型2 異常的變量名2){ // 程序代碼 }catch(異常類型2 異常的變量名2){ // 程序代碼 }
上面的代碼段包含了3個catch塊。
可以在try語句後面添加任意數量的catch塊。
如果保護代碼中發生異常,異常被拋給第一個catch塊。
如果拋出異常的數據類型與ExceptionType1匹配,它在這裡就會被捕獲。
如果不匹配,它會被傳遞給第二個catch塊。
如此,直到異常被捕獲或者通過所有的catch塊。
該實例展示了怎麼使用多重try/catch。
try { file = new FileInputStream(fileName); x = (byte) file.read(); }catch(IOException i) { i.printStackTrace(); return -1; }catch(FileNotFoundException f) //Not valid! { f.printStackTrace(); return -1; }
如果一個方法沒有捕獲一個檢查性異常,那麼該方法必須使用throws 關鍵字來聲明。throws關鍵字放在方法簽名的尾部。
也可以使用throw關鍵字拋出一個異常,無論它是新實例化的還是剛捕獲到的。
下面方法的聲明拋出一個RemoteException異常:
import java.io.*; public class className { public void deposit(double amount) throws RemoteException { // Method implementation throw new RemoteException(); } //Remainder of class definition }
一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開。
例如,下面的方法聲明拋出RemoteException和InsufficientFundsException:
import java.io.*; public class className { public void withdraw(double amount) throws RemoteException, InsufficientFundsException { // Method implementation } //Remainder of class definition }
finally關鍵字用來創建在try代碼塊後面執行的代碼塊。
無論是否發生異常,finally代碼塊中的代碼總會被執行。
在finally代碼塊中,可以運行清理類型等收尾善後性質的語句。
finally代碼塊出現在catch代碼塊最後,語法如下:
try{ // 程序代碼 }catch(異常類型1 異常的變量名1){ // 程序代碼 }catch(異常類型2 異常的變量名2){ // 程序代碼 }finally{ // 程序代碼 }
public class ExcepTest{ public static void main(String args[]){ int a[] = new int[2]; try{ System.out.println("Access element three :" + a[3]); }catch(ArrayIndexOutOfBoundsException e){ System.out.println("Exception thrown :" + e); } finally{ a[0] = 6; System.out.println("First element value: " +a[0]); System.out.println("The finally statement is executed"); } } }
以上實例編譯運行結果如下:
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 First element value: 6 The finally statement is executed
注意下面事項:
在Java中你可以自定義異常。編寫自己的異常類時需要記住下面的幾點。
可以像下面這樣定義自己的異常類:
class MyException extends Exception{ }
只繼承Exception 類來創建的異常類是檢查性異常類。
下面的InsufficientFundsException類是用戶定義的異常類,它繼承自Exception。
一個異常類和其它任何類一樣,包含有變量和方法。
// 文件名InsufficientFundsException.java import java.io.*; public class InsufficientFundsException extends Exception { private double amount; public InsufficientFundsException(double amount) { this.amount = amount; } public double getAmount() { return amount; } }
為了展示如何使用我們自定義的異常類,
在下面的CheckingAccount 類中包含一個withdraw()方法拋出一個InsufficientFundsException異常。
// 文件名稱 CheckingAccount.java import java.io.*; public class CheckingAccount { private double balance; private int number; public CheckingAccount(int number) { this.number = number; } public void deposit(double amount) { balance += amount; } public void withdraw(double amount) throws InsufficientFundsException { if(amount <= balance) { balance -= amount; } else { double needs = amount - balance; throw new InsufficientFundsException(needs); } } public double getBalance() { return balance; } public int getNumber() { return number; } }
下面的BankDemo程序示范了如何調用CheckingAccount類的deposit() 和withdraw()方法。
//文件名稱 BankDemo.java public class BankDemo { public static void main(String [] args) { CheckingAccount c = new CheckingAccount(101); System.out.println("Depositing $500..."); c.deposit(500.00); try { System.out.println("\nWithdrawing $100..."); c.withdraw(100.00); System.out.println("\nWithdrawing $600..."); c.withdraw(600.00); }catch(InsufficientFundsException e) { System.out.println("Sorry, but you are short $" + e.getAmount()); e.printStackTrace(); } } }
編譯上面三個文件,並運行程序BankDemo,得到結果如下所示:
Depositing $500... Withdrawing $100... Withdrawing $600... Sorry, but you are short $200.0 InsufficientFundsException at CheckingAccount.withdraw(CheckingAccount.java:25) at BankDemo.main(BankDemo.java:13)
在Java中定義了兩種類型的異常和錯誤。