一、异常分类
说明:1、所有异常都由Throwable继承而来,下一层分为error和Exception,Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误,应用程序不应该抛出这类对象。如果出现了这样的错误,除了通告用户,并尽力使程序安全的终止之外,再也无能为力,这种情况比较少见。
2、JAVA语言规范将派生于Error类或RuntimeException类的所有异常称为未检查异常(unchecked),所有的其他异常称为已检查异常(checked),编译器将核查是否为所有的已检查异常提供了异常处理器。
3、Exception类是在程序设计时需要重点关注的,它分为两个分支:RuntimeException和其它异常,由程序错误导致的异常属于RuntimeException,而程序本身没问题,但是由于像IO错误这类问题导致的异常属于其它异常。
派生于RuntimeException的异常包含下面几种情况,如果出现RuntimException异常就一定是你的问题:
不是派生于RuntimeException的其它异常包括:(1)错误的类型转换
(2)数组访问越界:ArrayIndexOutOfBoundsException
(3)访问空指针:NullPointerException
(1)试图在文件结尾后读取数据
(2)试图打开一个不存在的文件
(3)试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
二、何时抛出异常(throw用于出现异常时抛出异常,throws用于方法首部声明异常)
(1)调用一个抛出已检查异常的方法,例如FileInputStream构造器。
(2)程序运行过程中发现错误,并且利用throw语句抛出一个已检查异常。
说明:上述抛出的两种异常必须声明或捕获,告诉调用这个方法的程序员进行捕获
(3)程序出现错误,如a[-1]=0抛出ArrayIndexOutOfBoundsException
(4)Java虚拟机和运行时库出现的内部错误。
说明:这两种异常不需要声明/捕获,因为程序错误完全在我们的控制之下,可通过修正程序完成;Java内部错误,任何代码都具有抛出的潜能,我们对它没有任何控制能力。
总结:一个方法必须声明所有可能抛出的已检查异常,而为检查异常要么不可控制,要么就应该避免发生,如果方法没有声明所有可能发生的已检查异常,编译器就会给出一个错误。
注意:如果在子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能比超类方法中声明的异常更通用!
如果一个方法中声明将会抛出一个异常,则这个方法就有可能抛出一个这个类的异常或者这个类的某一子类的异常。
三、如何抛出异常
(1)不存在异常:需要自定义异常
派生于Exception的类或者派生于Exception子类的类,通常包含两个构造器,一个默认,一个带详细描述信息,以便可以调用超类Throwable的toString方法打印详细信息,方便调试。
(2)已存在异常:找到一个合适的异常类
(2)创建这个类的一个对象
(3)将对象抛出
四、捕获异常
语句:
try{
code
more code
more code
}catch(ExceptionType e){
handler for this type
}
可以有多个catch字句捕获多个异常。
说明:如果在try语句块中的任何代码抛出了一个在catch子句中说明的异常类,那么
(1)程序将跳过try语句块的其余代码
(2)程序将执行catch子句中的处理器代码
对抛出的异常最好的处理是传递给调用者,调用者必须对它进行处理或继续传递。
如果在try语句中的代码没有抛出任何异常,那么程序将跳过catch子句。
五、try catch finally语句执行顺序
InputStream in=new FileInputStream(...);
try{
//1
code that might throw exceptions
//2
}catch(IOException e){
//3
show error message
//4
}finally{
//5
in.close();
}
//6
上述代码执行顺序:
(1)代码没有抛出异常:1->2->5->6
(2)抛出一个被catch捕获的异常:
1)catch子句没有抛出异常:1->3->4->5->6
2)catch字句抛出了一个异常,异常被抛回方法调用者:1->3->5
(3)抛出了一个异常,但未被catch字句捕获:1->5
总结:finally字句总会被执行,继续往下执行(语句6)只有两种情况:一是没有抛出异常,另一个是抛出异常被catch字句捕获并处理,没有继续抛出。
六、带资源的try语句
try(Resource res=...){
word with res
}
若资源实现了Closeabel接口,try块退出时,自动调用res.close()关闭资源。这是JavaSE7的新功能,建议只要需要关闭资源,尽量使用带资源的try语句。还可指定多个资源,用分号分隔:
try(Scanner in=new Scanner();PrintWriter out=new Printer()){
}
六、使用异常机制的技巧
(1)异常处理不能代替简单的测试,只在异常情况下使用异常机制:
例如:判断栈空用if(!empty())条件句时间646ms,而catch(EmptyStackException e)时间21739ms
(2)不要过分的细化异常,一个try多个catch,当任何一个操作出现问题时,整个任务都可以取消
(3)利用异常层次结构:不要只抛出RuntimeException异常,应该寻找更加适当的子类或创建自己的异常类。不要只捕获throwable异常,否则会使代码更难度,更难维护。
(4)不要压制异常
(5)不要羞于传递异常,传递异常要比捕获异常更好,传递给高层方法通知用户发生了错误。