异常体系层
我们的关注点可能主要在四个类上:
- Throwable
- Error
- Exception
- RuntimeException
所有的异常都是由Throwable 继承而来,但在下一层立即分解为两个分支:Error 和 Exception。Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。Exception 层次分解为两个分支: RuntimeException 和 其他异常。
RuntimeException 异常
- 错误的类型转换 ClassCastException
- 数组访问越界 ArrayIndexOutOfBoundsException
-
受查异常
试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
Java语言规范将派生于 Error 异常或 RuntimeException 类的所有异常称为非受查(unchecked) 异常。所有其他的异常称为受查(checked)异常。
异常处理机制
遇到异常怎么办?要么自己想办法处理,要么就抛给别人。
捕获异常 try、catch 和 finally
- 首先是 try-catch 语句
基本语法如下:
try {
// 可能会发生异常的程序代码
} catch (Type1 id1){
// 捕获并处置try抛出的异常类型Type1
} catch (Type2 id2){
//捕获并处置try抛出的异常类型Type2
}
关键词 try 后面的大括号区域为可能发生异常的代码,称为监控区。当抛出异常或者出现运行时异常,然后由 Java 运行时系统巡展匹配 catch 子句。若有匹配的catch子句,则运行其异常处理代码,try-catch语句结束。
匹配规则:抛出的异常属于 catch 语句捕获异常类及子类,则匹配成功。
一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会,并且 try 里面如果有没有走完的语句也会自动跳过。
- try-catch-finally
这个很简单,无论 try-catch 是正常结束还是发生异常捕获,都会执行 finally 语句,如果在 finally 之前发生了 return,那么 finally 语句块会在 retrun 之前执行。
try {
// 可能会发生异常的程序代码
} catch (Type1 id1){
// 捕获并处置try抛出的异常类型Type1
} catch (Type2 id2){
//捕获并处置try抛出的异常类型Type2
}finally{
//do something
}
抛出异常
任何 Java 代码都可以抛出异常,语句通过 throw 抛出、方法则是 throws。
为什么要 throw 异常?
如果一个方法可能会出现异常,但是没有能力处理这种又一次,则可以在方法声明处用 throws 语句来抛出。throws 语句可以同时声明抛出多个异常,语法格式如下:
void methodName()throws Exception1,Exception2,Exception3{
}
- 如果是不可查异常,那么不用声明,编译仍然可以通过,但是运行时会被JVM 抛出。
- 如果是可查异常,要么 try-catch,要么 throws,否则编译无法通过。
- 当抛出了异常时,该方法的调用者才会处理或者重新抛出该异常。
- 调用 throws 异常的方法,必须 try-catch 调用语气,且 catch 的异常必须是抛出异常的同类或者父类。
Java7与异常
try-with-resources
所谓的try-with-resources,是个语法糖。实际上就是自动调用资源的close()函数。和Python里的with语句差不多。
不使用try-with-resources,我们在使用io等资源对象时,通常是这样写的:
String getReadLine() throws IOException {
BufferedReader br = new BufferedReader(fileReader);
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
使用try-with-recources的写法:
String getReadLine() throws IOException {
try (BufferedReader br = new BufferedReader(fileReader)) {
return br.readLine();
}
}
编绎器自动在try-with-resources后面增加了判断对象是否为null,如果不为null,则调用close()函数的的字节码。
只有实现了java.lang.AutoCloseable接口,或者java.io.Closable(实际上继随自java.lang.AutoCloseable)接口的对象,才会自动调用其close()函数。
**
自定义异常
- 定义一个派生于Exception的类,或者派生于Exception子类的类。
- 习惯上,定义的类应该包含两个构造器。一个默认的构造器,另一个是带有详细描述信息构造器。
class FileFormatException extends IOException
{
public FileFormatException(){}
public FileFormatException(String message)
{
super(message);
}
}