第四節、throw和throws
一、throw
當你想顯式的拋出一個異常或拋出一個你自己定義的異常時,你可以使用throw語句。例子:
package Examples;
public class ThrowDemo{
public static void main(String[] args){
try{
int i=Integer.parseInt(args[0]); //將字符串數組中的第一個參數轉換成int類型
if(i<=0){
// throw是一個動作,而後面則創建了一個IllegalArgumentException類的
//實例,所有Java內置的運行時異常有兩個構造函數:一個沒有參數,一
//個帶有一字符串參數;使用第二種形式時,參數指定描述異常的字符串
throw new IllegalArgumentException("Illegal Arguments!");
}else {
System.out.println("Parameter is OK!");
}
}catch(IllegalArgumentException e){
System.out.println(e);
}
}
}
下面是運行時的三種情況:
C:/JavaApp>java Examples.ThrowDemo
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Examples.ThrowDemo.main(ThrowDemo.java:5)
C:/JavaApp>java Examples.ThrowDemo 0
java.lang.IllegalArgumentException: Illegal Arguments!
C:/JavaApp>java Examples.ThrowDemo 10
Parameter is OK!
二、throws
如果一個方法可以導致了一個異常但不處理它,那麼它必須指定這種行爲以使方法的調用者可以保護它們自己而不發生異常。做到這點你可以在方法聲明中包含一個throws子句來列舉一個方法可能引發的所有異常類型。當方法中引發的是Error或RuntimeException及它們子類以外類型的異常的話,那麼必須使用throws子句並列舉出這些異常的類型,否則會導致編譯錯誤。而方法中引發的是Error或RuntimeException及它們子類類型的異常的話,可以不用在throws列表中包括。
爲了加深對throw和throws的認識,我們使用了一個錯誤的例子,然後再更正它。
錯誤的例子:
package Examples;
public class ThrowsDemo{
static void throwOne(int i) { //這裏會導致編譯錯誤,IllegalAccessException不是Error
// 或RuntimeException及它們的子類,必須聲明
//throws IllegalAccessException
int j=36/i;
System.out.println("Inside throwOne()");
throw new IllegalAccessException("Throws Demo");
}
public static void main(String[] args){
throwOne(Integer.parseInt(args[0])); //這裏沒有異常處理,會導致程序終止
System.out.println("End ThrowsDemo!");
}
}
要使上面的例子能成功運行,必須在main()方定義try/catch代碼塊來捕獲該異常。
更改後的例子:
package Examples;
public class ThrowsDemo{
// throws 後面如有不同異常類型需用逗號隔開
// 函數聲明爲static,這樣在main()方法中可以直接引用
static void throwOne(int i) throws IllegalArgumentException {
int j=36/i; // 這裏有可能出現被0除的錯誤
System.out.println("Inside throwOne()");
throw new IllegalArgumentException("Throws Demo"); //顯式拋出一個異常
}
public static void main(String[] args){
try{
throwOne(Integer.parseInt(args[0])); //讀取命令行字符串數組的第一個參數
}catch(IllegalAccessException e){
System.out.println("Caught : "+e);
}catch(ArithmeticException e){
System.out.println("Caught : "+e);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Caught : "+e);
} catch(NumberFormatException e){
System.out.println("Caught : "+e);
}
System.out.println("End ThrowsDemo!");
}
}
下面是四種不同運行時的結果:
C:/JavaApp>java Examples.ThrowsDemo
Caught : java.lang.ArrayIndexOutOfBoundsException: 0
End ThrowsDemo!
C:/JavaApp>java Examples.ThrowsDemo 0
Caught : java.lang.ArithmeticException: / by zero
End ThrowsDemo!
C:/JavaApp>java Examples.ThrowsDemo 1
Inside throwOne()
Caught : java.lang.IllegalAccessException: Throws Demo
End ThrowsDemo!
C:/JavaApp>java Examples.ThrowsDemo k
Caught : java.lang.NumberFormatException: For input string: "k"
End ThrowsDemo!
第五節、創建自己的異常子類
建立自己的異常類型很簡單,只要擴展Exception或其某個子類就可以了。Exception繼承了Throwable提供的一些方法,因此所有異常,包括你自己創建的都可以獲得這些方法,它們顯示在下表中:
方法 |
描述 |
Throwable fillInStackTrace() |
返回一個包含完整堆棧軌跡的Throwable對象,該對象可能被再次引發 |
String getLocalizedMessage() |
返回一個異常的局部描述 |
String getMessage() |
返回一個異常的描述 |
void printStackTrace() |
顯示堆棧軌跡 |
void printStackTrace(PrintStreamstream) |
把堆棧軌跡送到指定的流 |
Void printStackTrace(PrintWriterstream) |
把堆棧軌跡送到指定的流 |
String toString() |
返回一個包含異常描述的字符串。當輸出一個Throwable對象時,該方法被println()調用 |
例子:
package Examples;
public class MyException extends RuntimeException {
//如果不重載toString()方法的話,顯示的是該Exception的完整名稱,包括所在包。
public String toString(){
return "MyException: Error here.";
}
}
class MyExceptionDemo{
public static void main(String[] args){
try{
int i=Integer.parseInt(args[0]);
System.out.println("i is :"+i);
if(i<=0) throw new MyException();
}catch(NumberFormatException e){
System.out.println("Caught: "+e);
}catch(MyException me){
System.out.println("Caught: "+me);
}
}
}