Java语言规范讲派生于Error类或RuntimeException类的所有异常称为非受查异常,所有其他的异常称为受查异常。
一个方法必须声明所有可能抛出的受查异常,二非受查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。如果方法没有声明所有可能发生的受查异常,编译器就会发出一个错误消息。
注意:如果在子类中覆盖了超类的一个方法,子类方法中声明的受查异常不能比超类方法中声明的异常更通用,也就是说,子类方法中可以抛出更特定的异常,或者根本不抛出任何异常。特别需要说明的是,如果超类方法没有抛出任何受查异常,子类方法也不能抛出任何受查异常,那么这个方法就必须捕获方法代码中出现的每一个受查异常。
在JavaSE7中,同一个catch子句中可以捕获多个异常类型。例如,假设对应缺少文件和未知主机异常的动作是一样的,就可以合并catch子句:
try{
*code...*
}catch(**FileNotFoundException | UnknowHostException e**){
*code...*
}catch(Exception){
*code...*
}
只有当捕获的异常类型彼此之间不存在子类关系时才需要这个特性。(捕获多个异常时,异常变量隐含为final变量,因为不能为变量引用赋不同的值。)
在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。
基本方法:
try{
*code...*
}catch(SQLException e){
throw new ServletException("database error:" + e.getMessage());
}
可以有一个更好的处理方法,并且将原始异常设置为新异常的“原因”:
try{
*code...*
}catch(SQLException e){
Throwable se = new ServletException("database error");
se.initCause(e);
throw se;
}
当捕获异常时,就可以使用 Throwable e = se.getCause(); 重新得到原始异常。
*带资源的try语句
资源属于一个实现了AutoCloseable接口的类(Closeable是它的子接口),JavaSE7为以下的代码提供了一个很有用的方式。
假设有以下的代码:
*open a resource*
try{
*code...*
}finally{
*close the resource*
//这里close方法会抛出异常。
}
如果在try语句块中的代码抛出了一些非IOException的异常,这些异常只有这个方法的调用者才能给预处理。执行finally语句块,并调用close方法。而close方法本身也有可能抛出IOException异常。当出现这种情况时,原始的异常将会丢失,转而抛出close方法的异常。
如果想要获取第一个异常,可以有以下的方式解决:
InputStream in = ...;
Exception ex = null;
try{
try{
*code...*
}catch(Exception e){
ex - e;
throw ex;
}
}finally{
try{
in.close();
}catch(Exception e){
if(ex == null) throw e;
}
}
而JavaSE7中关闭资源的处理会容易许多:
try(*resource res = ...*){
*code...*
}
try块退出时,会自动调用res.close()。
//例子
try(Scanner in = new Scanner(new FileInputStream("xxxx"), "UTF-8")){
while(in.hasNext())
System.out.println(in.next());
}
这个块正常退出或存在一个异常时,都会调用in.close()方法,就好像使用了finally块一样(带资源的try语句本身也可以有catch子句和一个finally子句,这些子句会在关闭资源后执行)。
如果try块抛出一个异常,而且close方法也抛出一个异常,原来的异常会重新抛出,而close方法抛出的异常会“被抑制”。被抑制异常将自动捕获并由addSuppressed方法增加到原来的异常。