第四节、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);
}
}
}