------- android培训、java培训、期待与您交流! ----------
Java类库中已经定义了很多异常类,然而在实际开发过程中,可能会产生一些我们的程序特有的异常,此时就需要我们自己定义异常,方便做出更具有针对性的声明和处理,此时就需要引入自定义异常。
1. 自定义异常格式
我们还是以前面除法算数异常为例,只不过我们要额外定义一个规则:除数不能为零,也不能为负。那么除数为零的算数异常Java类库中已经进行了描述,除数不能为负的异常就需要我们自己定义了。定义格式如下:
class MinusDivisorException extendsException{}
通过上述格式可以看出,自定义异常类的方式和定义普通类是类似的,但要注意两点:
(a) 异常类名最好添加Exception后缀,提高代码阅读性;
(b) 一定要继承该体系的父类Exception,否则该类就不是实际上的异常类,无法被“抛出”。
定义该异常类的目的暂时只是为了能够创建自定义异常对象,因此,并没有为该自定义异常类定义任何内容。
2. 自定义异常类的应用
代码1:
class MinusDivisorException extends Exception{}
class MathTools
{
//方法内抛出异常,要么在方法内try-catch处理,要么声明异常
public static int division(int x, inty)throws MinusDivisorException
{
/*
当除数y小于0时
通过关键字throw“抛出”MinusDivisorException异常对象
停止当前代码的继续执行
*/
if(y < 0)
throw new MinusDivisorException();
return x/y;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
//到了主函数就必须try-catch处理了,否则就是默认处理
try
{
int x = 5, y = -1;
int result =MathTools.division(x, y);
System.out.println(x+"/"+y+"= "+result);
}
catch (MinusDivisorException e)
{
//依旧为方便演示,简单处理
System.out.println(e1.toString());
System.out.println("除数不能为负!");
}
System.out.println("over");
}
}
运行结果为:
MinusDivisorException
除数不能为负!
over
代码1就是自定义异常的简单应用,由于MinusDivisorException是自定义异常,它并不存在于Java类库中,当除数真的是负数的时候,Java虚拟机是不会自动识别该异常,并抛出的,所以此时就需要通过代码进行判断,手动封装异常对象抛出,就像division方法中定义的那样。
那么在使用自定义异常类的时候需要注意两点:
(a) 因为是在方法内手动抛出异常,那么就必须按照前述的两种处理异常的方式进行处理:要么就地try-catch处理,要么在方法上声明该异常,表示将问题继续抛给调用者处理。当然,如果什么都不做,就会编译失败。不过这里有个例外,后面细说。
(b) division方法中使用了新的关键字“throw”手动抛出了MinusDivisorException对象。关键字“throw”有别于“throws”,注意两者的区分,同样也会在后面会详细讲述。
3. 定义异常信息
代码1的运行结果除了打印在控制台上的两行字符串以外,就只有第一行的异常类名了。换句话说没有像类似代码4运行后提示的具体异常信息。显然,这是因为我们并没有为MinusDivisorException异常类定义任何内容。
通过阅读Throwable类的API文档并结合该类的源码,可知该类通过如下方式定义(简化版,方便理解):
代码2:
classThrowable
{
private String message;
Throwable(String message)
{
this.message = message;
}
public String getMessage()
{
return message;
}
}
Exception类继承了Throwable类,并通过其父类的构造方法初始化,且
没有复写其他方法
:
代码3:
class Exception extends Throwable
{
Exception(String message)
{
super(message);
}
}
上述代码中的message就是异常信息字符串,那么当创建异常对象的时候可以将异常信息字符串作为参数传入对应异常类的构造方法,为message初始化,然后通过toString方法打印该信息(调用toString时会自动调用getMessage方法,参见API文档)。
因此,我们在定义自定义异常类的时候也应该参考父类的构造方法对异常信息进行初始化:
代码4:
class MinusDivisorException extends Exception
{
//直接从父类继承了message字符串成员变量
//参考父类的初始化动作
MinusDivisorException(String message)
{
super(message);
}
}
class MathTools
{
public static int division(int x, inty)throws MinusDivisorException
{
if(y < 0)
//传入异常信息
throw new MinusDivisorException("除数不能为负!");
return x/y;
}
}
class ExceptionDemo2
{
public static void main(String[] args)
{
try
{
int x = 5, y = -1;
int result =MathTools.division(x, y);
System.out.println(x+"/"+y+"= "+result);
}
catch (MinusDivisorException e)
{
System.out.println(e.toString());
//这里就不必再手动打印异常信息了
//System.out.println("除数不能为负!");
}
System.out.println("over");
}
}
运行结果为:
MinusDivisorException:除数不能为负!
over
这样就可以像Java类库中已有异常类那样报出异常信息了。当然我们也可以在自定义异常类中加入自定义异常信息,比如直接提示负数值为多少等等。
4. 为什么要继承Exception类
无论是错误(Error)还是异常(Exception),他们的共性特征就是“可抛性”。而这一特性只有某个类通过继承成为异常继承体系的一元才能具备,才能通过throws关键被声明,才能通过throw关键字被抛出对应的异常对象。
另外,能否直接继承Throwable类呢?实际上,无论是什么样的问题,大多都可以归结到Error类或者Exception类中,如果没有特别的需求,没有必要自定义新的“派系”。
小知识点1:throws和throw关键字的区别
1) 语法区别
(a) 使用位置
throws用在方法上;
throw用在方法内。
(b) 定义方式
throws后接异常类名,可接多个异常,用逗号分隔;
throw后接异常对象,只能接一个异常对象。
2) 作用区别
throws的作用是异常声明和异常传递:
(a) 告诉程序员,使用该方法需要异常处理;
(b) 当发生异常,而没有try-catch处理时,将异常传递给上级调用者。
throw的作用是异常抛出。
当条件满足时,抛出异常,跳转程序。