java中所有的异常都是由throwable继承而来的,他的下一层分解为两个分支:Error和Exception。
Error类主要由于java运行时系统内部错误和资源耗尽错误,程序不应该抛出这种类型的对象,这种情况很少见。
Exception层次结构分为两个分支:一个派生于RuntimeException,另一个是其他类型异常。划分依据 :由程序导致的异常属于RuntimeException。而程序本身没问题,由于类似于I/O这类问题导致的异常属于其他异常。
RuntimeException包含以下情况:
1.数组类型错误
2.数组访问越界
3.访问空指针
其他异常包括:
1.试图在文件尾部后面读取数据
2.试图打开一个不存在的文件
3.试图根据给定的字符串朝赵Class对象,而该字符串表示的类并不存在。
小结:如果出现RuntimeException异常,那么就一定是你的问题。
java将派生于Error类或RuntimeException类的所有异常称为未检查异常。所有其他的异常称为已检查异常。
下面4种情况应抛出异常:(前两种必须!)
1.调用一个抛出已检查异常的方法,例如,FileInputStream构造器
2.程序运行过程中发生错误,并利用throw语句抛出一个已检查异常。
3.程序出现错误
4.java虚拟机和运行时库出现内部错误。
如果一个方法可能抛出多个异常,则必须在方法的首部勒出所有的异常类。每个异常类之间用逗号隔开。
小结:一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控(Error),要么应避免发生(RuntimeException)
警告:如果在之类中覆盖了超类中的一个方法,则之类中声明的已检查异常不能比超类方法中声明的异常更通用。若超类方法没抛出任何已检查异常,则子类也不能。
捕获异常:
对于一个普通异常,通常,最好的方法是什么也不做,而是将异常传递给调用者。由调用者处理,此时,就必须声明这个方法可能会抛出一个异常,例如IOException。
如果调用了一个抛出已检查异常的方法,就必须对它进行处理,或者将它继续进行传递。通常捕获那些知道如何处理的异常麻将不知怎样处理的异常继续进行传递,此时必须在方法的首部添加一个throws说明符。
警告:如果编写一个覆盖超类的方法,超类如果没有抛出异常,则该方法必须捕获方法代码中出现的每一个已检查异常。不能再子类的throws出现超过超类范围的说明。
捕获多个异常时,异常变量银行为final变量。捕获多个异常时代码看起来更简单,更高效。生成的字节码只包含一个对应公共catch子句的代码块。
printStackTrace可以打印出堆栈跟踪的文本信息;
再次抛出异常与异常链(包装技术):
在catch子句中可以抛出一个异常,用来改变异常的类型。如果开发了一个供其他程序员使用的子系统,那么用于表示子系统故障的异常类型可能会产生多种解释,例如ServletException。下面是捕获异常并在此抛出的方法:
try
{
access the database
}
catch(SQLException)
{
throw new ServletException("database error :"+e.getMessage());
}
可以有更好的处理方法,并将原始异常设置为新异常的“原因”:
try
{
access the database
]
catch(SQLException)
{
Throwable se = new ServletException("database error");
se.initCause(e);
throw se;
}
当捕获到异常时,就可以使用下面这条语句重新得到原始异常:
Throwable e = se.getCause();
小结:推荐使用这种包装技术,可以让用户抛出子系统中的高级异常,而不会丢失原始异常的细节。
finally语句:
无论是否发生异常,finally都会被执行,通常用来关闭数据库连接。有时推荐使用try/catch和try/finally语句块。内层负责关闭输入流,外层确保报告出现的错误。
InputStream in = ......;
try
{
try
{
code that might throw exceptions
}
finally{in.colse()}
}
catch(IOException e)
{
show error message
}
警告:当finally子句包含return语句时,此时如果try中也有return,则finally中的会覆盖掉try中的return。
带资源的try语句:(java SE 7)
假设资源属于一个实现了AutoCloseable接口的类,(AutoCloseable接口有一个方法:void close()throws Exception),Java SE 7提供了最简形式:
try(Resource res=.......)
{
work with res
}
try 块退出时,会自动调用res.close()方法;下面给出一个读取一个文件中所有单词的例子:
try(Scanner in = new Scanner(new FileInputStream("/user/share/dict/words"));
PrintWriter out = new PrintWriter("out.txt"))
{
while(in.hasNext()) system.out.println(in.next());
}
注释:带资源的try也可以由catch和finally,他们会在资源关闭后执行;
异常机制的使用技巧:(5,6总结为:早抛出,晚捕获)
1.异常处理不能代替简单的测试(比如对可能为空的用if进行判断)
2.不要过分细化异常
3.利用异常层次结构(包装技术)
4.不要压制异常
5.检查错误时,苛刻比放任好
6.适当传递异常
7.合理的程序不应该捕捉运行时异常