什么是异常
异常都继承于Throwable类,其有两个继承类,Error和Exception,Error是指发生了程序无法处理的严重错误,程序无法处理,当然也无法catch,只能尽力保证程序安全终止;Exception是我们应该关注的层次结构,其又划分出两个分支——RuntimeException和其他异常,如IO类的错误
如果方法中可能产生异常就可以在方法标签后显式声明出来,如果一个方法可能抛出多个异常,那么必须在方法首部列出所有的异常类,每个类之间用逗号隔开
public Image loadImage(Stirng s) throws IOException,FileNotFoundException {}
如果父类方法中声明了异常,那么子类覆盖父类方法时候声明的已检查异常不能比父类更通用,也就是说子类可以抛出更特定的异常,或者根本不抛出异常。
需要特别注意的是,如果超类方法没有声明抛出任何异常,那么子类方法也不能声明抛出异常
创建自定义的异常类
总有标准API不能满足需求的时候,这时候自定义异常类就变得顺理成章。
class FileFormatException extends IOException {
public FileFormatException() {
}
public FileFormatException(String s) {
super(s);
}
}
public static String readData(BufferedReader in) throws FileFormatException {
//do sth
throw new FileFormatException();
}
捕获异常
try/catch组合捕获异常
- 如果在try语句块中发生了能被catch语句捕获的异常,则会跳过try语句块中剩余的语句,进入catch语句块。
try {
System.out.println("do sth 1");
throw new IOException();
//System.out.println("do sth 2");
} catch (IOException e) {
System.out.println("do sth 3");
System.out.println("do sth 4");
}
System.out.println("do sth 5");
以上输出
do sth 1
do sth 3
do sth 4
do sth 5
以上输出do sth 1 do sth 3 do sth 4 do sth 5
注: 同一个catch语句可以捕获多个异常,形式为catch(FileNotFoundException | UnKnownHostException),只有当捕获当异常类型之间不存在子类关系时才需要这个特性。
- 如果抛出了不能被catch的异常,方法将退出,程序如果没有更上层的方法处理异常,程序也将退出
try {
System.out.println("do sth 1");
int[] arrays = {1,2};
System.out.println(arrays[2] > 4);
throw new IOException();
//System.out.println("do sth 2");
} catch (IOException e) {
System.out.println("do sth 3");
System.out.println("do sth 4");
}
System.out.println("do sth 5");
以上输出
do sth 1
- 如果catch语句块中也抛出了异常,那么方法将会在catch语句块抛出异常处退出
try {
System.out.println("do sth 1");
throw new IOException();
//System.out.println("do sth 2");
} catch (IOException e) {
System.out.println("do sth 3");
throw new ArrayIndexOutOfBoundsException();
//System.out.println("do sth 4");
}
//System.out.println("do sth 5");
以上输出
do sth 1
do sth 3
总结一下,程序抛出了异常,如果能被catch处理,就在处理后继续运行,否则就会在抛出异常处中断
finally语句
但是我们很多时候需要考虑资源释放,靠上述的模型是无法处理一些资源释放的工作的,finally语句就是一个很好的解决方案,它的作用在于,无论是否抛出异常,finally中的语句都会执行。看下面一个例子
try{
//1
code that might throw Exception
//2
}catch {
//3
show throw message
//4
}finally {
//5
do some close job
}
//6
- 如果程序没有抛出异常,执行1、2、5、6
- 如果程序抛出了被catch并正确处理的异常,则执行1、3、4、5、6
- 如果catch住了异常但catch语句中也抛出了异常,则执行1、3、5
- 如果抛出了不能被catch但异常,则执行1、5
我们也可以使用不带catch的try/finally组合,无论是否抛出异常,finally语句块都会被执行,当然方法调用者要考虑处理可能抛出的异常
try{
}finally {
}
这里强烈建议使用try/catch和try/finally的组合,提高代码的清晰度,比如
try {
try {
}finally{
do some close job
}
}catch(Exception e) {
show some excption message
}
内部try/finally组合保证一定能关闭资源,外部try/catch组合保证异常能被捕获,关键是能捕获finally语句块中的内容
这里注意return语句带来的影响,如果方法有返回值,则在return语句执行之前,会先执行finally中的内容,如果finally语句中也有return语句,则其会直接覆盖方法中的return
try {
n = n * n;
return n;
} catch (Exception e) {
} finally {
return 0;
}
以上输出
0
如果是在catch语句中return,那就把catch想象成另一个try即可。