1.1.4. catch
抛出的异常必须在某处得到处理,这个点就是异常处理程序。针对每个要捕获的异常,准备相应的处理程序。异常处理程序紧跟着try块,以关键字catch表示。
每个catch子句,看起来就像是接收一个且只接收一个特殊异常类型的方法。当异常发生后,异常处理机制会搜寻参数与异常类型匹配的第一个异常处理器,然后进入catch子句执行,此时认为异常得到了处理。一旦catch子句结束,则处理程序的查找过程结束。
在查找异常处理器时,并不要求抛出的异常与异常处理器所声明的异常完全匹配。派生类的对象也可以匹配基类的处理器。
1 |
2
3
4
5
6
7
8
9
10
11
12
private String tryException(){
try {
// 监控区域
return throwException();
}catch (RuntimeException e){
// 处理 RuntimeException 情况
}
catch (Exception e){
// 处理 Exception 情况
}
return “”;
}
顺序,异常处理机制会搜索第一个匹配的异常处理器,因此catch语句的顺序至关重要,通常将具体类型前置,通用类型后置。
1.1.5. finally
对于一些代码,可能会希望无论try块中是否抛出异常,他们都会执行。为了达到效果,可以在异常处理后面加上finally子句。
对于没有垃圾回收和析构函数自动调用机制的语言来说,finally非常重要。它是程序员能够保证在任何情况下,内存总能得到释放。但在Java中存在垃圾回收机制,内存释放不再是个问题。当要把除内存外的资源恢复到他们的初始化状态时,就需要使用finally子句。常见的资源包括:网络链接、文件句柄、显示锁等。
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
private String tryException(){
try {
// 监控区域
return throwException();
}catch (RuntimeException e){
// 处理 RuntimeException 情况
}
catch (Exception e){
// 处理 Exception 情况
}finally {
// 对 网络链接、文件句柄、锁等资源进行处理
}
return “”;
}
1.2 方法异常说明
Java鼓励将方法可能会抛出的异常告知使用该方法的客户端。这种做法,使得调用者能知道在代码中可以获取所有的异常。
异常说明在方法声明中使用附加的关键字throws,后面接一个所有潜在异常类型列表,所以方法签名变成:
1 |
2
3
4
5
// 方法异常说明
private List<String> readFromFile(String filePath) throws IOException {
Path path = Paths.get(filePath);
return Files.readAllLines(path, Charset.defaultCharset());
}
代码必须和异常说明保存一致。如果方法里面的代码产生了异常却没有被处理,编译器会报错,要么处理这个异常,要么在异常说明列表中添加这个异常类型。
当然,可以在方法签名中声明异常,实际上并不抛出。这样可以为异常占个位置,以后可以抛出该异常而不用修改调用代码。
被检查异常,这种在编译阶段被强制检查的异常成为被检查异常。
备注: 被检查异常,可以通过反射机制获取异常列表。
1.3 异常的限制
当覆盖方法时,只能抛出在基类方法的异常列表中列出的异常,这意味着当基类使用的代码应用到其派生类对象的时候,程序一样能正常工作。
1.3.1. 方法重写
尽管在继承过程中,编译器会对异常说明做强制要求,但异常说明并不是方法类型的一部分,方法类型由方法名和参数类型组成。因此不能基于异常说明来重载方法。
对于方法重写时子类方法中的异常列表,要求要宽松得多。
-
子类方法异常列表与父类完全一致
-
子类方法异常列表是父类方法异常列表的子集
-
子类方法没有抛出异常
-
子类方法抛出父类方法异常的子异常
具体代码如下:
1 |
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 父类接口
public interface FileReader {
List<String> readFromFile(String filePath) throws IOException;
}
class FileReader1 implements FileReader{
// 子类方法异常列表与父类完全一致
@Override
public List<String> readFromFile(String filePath) throws IOException {
return null;
}
}
class FileReader2 implements FileReader{
// 子类方法抛出父类方法异常的子异常
@Override
public List<String> readFromFile(String filePath) throws FileNotFoundException {
return null;
}
}
class FileReader3 implements FileReader{
// 子类方法没有抛出异常
@Override
public List<String> readFromFile(String filePath){
return null;
}
}
1.3.2. 方法重载
Ja